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

phy54616.c (147807B)


      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:        phy54616.c
      8  * Purpose:     PHY driver for BCM54616 and BCM54616S
      9  */                        
     10 
     11 #include <sal/types.h>
     12 #include <sal/core/spl.h>
     13 #include <shared/bsl.h>
     14 #include <soc/drv.h>
     15 #include <soc/debug.h>
     16 #include <soc/error.h>
     17 #include <soc/phyreg.h>
     18 
     19 #include <soc/phy.h>
     20 #include <soc/phy/phyctrl.h>
     21 #include <soc/phy/drv.h>
     22 
     23 #include "phydefs.h"      /* Must include before other phy related includes */
     24 
     25 #if defined(INCLUDE_PHY_54616) || defined(INCLUDE_PHY_54618SE) || defined(INCLUDE_PHY_54618E)
     26 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     27 #include "phyident.h"
     28 #include "phyreg.h"
     29 #include "phyfege.h"
     30 #include "phy54616.h"
     31 
     32 #define AUTO_MDIX_WHEN_AN_DIS   0       /* Non-standard-compliant option */
     33 #define DISABLE_CLK125          0       /* Disable if unused to reduce */
     34                                         /*  EMI emissions */
     35 
     36 #define PHY_IS_BCM54616S(_pc)  PHY_FLAGS_TST((_pc)->unit, (_pc)->port, \
     37                                               PHY_FLAGS_SECONDARY_SERDES)
     38 #define PHY_IS_BCM54618E(_pc)  PHY_MODEL_CHECK((_pc), \
     39                                                 PHY_BCM54618E_OUI, \
     40                                                 PHY_BCM54618E_MODEL)
     41 #define PHY_IS_BCM54618SE(_pc) PHY_MODEL_CHECK((_pc), \
     42                                                 PHY_BCM54618SE_OUI, \
     43                                                 PHY_BCM54618SE_MODEL)
     44 #define PHY_IS_BCM54618SE_OR_BCM54618E(_pc) \
     45                 (PHY_IS_BCM54618SE((_pc)) || PHY_IS_BCM54618E((_pc)))
     46 
     47 #define SOC_IF_ERROR_BREAK(op, __rv__)           \
     48                 if ( ((__rv__) = (op)) < 0 ) {   \
     49                     break;                       \
     50                 }
     51 
     52 STATIC int _phy_54616_no_reset_setup(int unit, soc_port_t port);
     53 STATIC int _phy_54616_medium_change(int unit, soc_port_t port,int force_update);
     54 STATIC int _phy_54616_copper_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability);
     55 STATIC int _phy_54616_fiber_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability);
     56 STATIC int _phy_54616_fiber_ability_advert_set(int unit, soc_port_t port,soc_port_ability_t *ability);
     57 STATIC int phy_54616_duplex_set(int unit, soc_port_t port, int duplex);
     58 STATIC int phy_54616_speed_set(int unit, soc_port_t port, int speed);
     59 STATIC int phy_54616_master_set(int unit, soc_port_t port, int master);
     60 STATIC int phy_54616_autoneg_set(int unit, soc_port_t port, int autoneg);
     61 STATIC int phy_54616_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode);
     62 STATIC int phy_54616_speed_get(int unit, soc_port_t port, int *speed);
     63 STATIC int phy_54616_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability);
     64 
     65 /*
     66  * Function:
     67  *      _phy_54618e_cl45_reg_read
     68  * Purpose:
     69  *      Read Clause 45 Register using Clause 22 register access
     70  * Parameters:
     71  *      unit      - StrataSwitch unit #.
     72  *      pc        - Phy control
     73  *      flags     - Flags
     74  *      dev_addr  - Clause 45 Device
     75  *      reg_addr  - Register Address to read
     76  *      val       - Value Read
     77  * Returns:
     78  *      SOC_E_XXX
     79  */
     80 
     81 STATIC int
     82 _phy_54618e_cl45_reg_read(int unit, phy_ctrl_t *pc, uint32 flags, 
     83                           uint8 dev_addr, uint16 reg_addr, uint16 *val)
     84 {
     85     /* Write Device Address to register 0x0D (Set Function field to Address)*/
     86     SOC_IF_ERROR_RETURN
     87         (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f)));
     88 
     89     /* Select the register by writing to register address to register 0x0E */
     90     SOC_IF_ERROR_RETURN
     91         (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr));
     92 
     93     /* Write Device Address to register 0x0D (Set Function field to Data)*/
     94     SOC_IF_ERROR_RETURN
     95         (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 
     96                             ((0x4000) | (dev_addr & 0x001f))));
     97 
     98     /* Read register 0x0E to get the value */
     99     SOC_IF_ERROR_RETURN
    100         (PHY54616_REG_READ(unit, pc, flags, 0x00, 0x0E, val));
    101 
    102     return SOC_E_NONE;
    103 }
    104 
    105 /*
    106  * Function:
    107  *      _phy_54618e_cl45_reg_write
    108  * Purpose:
    109  *      Write Clause 45 Register content using Clause 22 register access
    110  * Parameters:
    111  *      unit      - StrataSwitch unit #.
    112  *      pc        - Phy control
    113  *      flags     - Flags
    114  *      dev_addr  - Clause 45 Device
    115  *      reg_addr  - Register Address to read
    116  *      val       - Value to be written
    117  * Returns:
    118  *      SOC_E_XXX
    119  */
    120 
    121 STATIC int
    122 _phy_54618e_cl45_reg_write(int unit, phy_ctrl_t *pc, uint32 flags, 
    123                            uint8 dev_addr, uint16 reg_addr, uint16 val)
    124 {
    125     /* Write Device Address to register 0x0D (Set Function field to Address)*/
    126     SOC_IF_ERROR_RETURN
    127         (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f)));
    128 
    129     /* Select the register by writing to register address to register 0x0E */
    130     SOC_IF_ERROR_RETURN
    131         (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr));
    132 
    133     /* Write Device Address to register 0x0D (Set Function field to Data)*/
    134     SOC_IF_ERROR_RETURN
    135         (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 
    136                             ((0x4000) | (dev_addr & 0x001f))));
    137 
    138     /* Write register 0x0E to write the value */
    139     SOC_IF_ERROR_RETURN
    140         (PHY54616_REG_WRITE(unit, pc, flags, 0x00, 0x0E, val));
    141 
    142     return SOC_E_NONE;
    143 }
    144 
    145 /*
    146  * Function:
    147  *      _phy_54618e_cl45_reg_modify
    148  * Purpose:
    149  *      Modify Clause 45 Register contents using Clause 22 register access
    150  * Parameters:
    151  *      unit      - StrataSwitch unit #.
    152  *      pc        - Phy control
    153  *      flags     - Flags
    154  *      reg_bank  - Register bank
    155  *      dev_addr  - Clause 45 Device
    156  *      reg_addr  - Register Address to read
    157  *      val       - Value 
    158  *      mask      - Mask for modifying the contents of the register
    159  * Returns:
    160  *      SOC_E_XXX
    161  */
    162 
    163 STATIC int
    164 _phy_54618e_cl45_reg_modify(int unit, phy_ctrl_t *pc, uint32 flags, 
    165                             uint8 dev_addr, uint16 reg_addr, uint16 val,
    166                             uint16 mask)
    167 {
    168     uint16 value = 0;
    169 
    170     SOC_IF_ERROR_RETURN
    171         (PHY54618E_CL45_REG_READ(unit, pc, flags, dev_addr, reg_addr, &value));
    172 
    173     value = (val & mask) | (value & ~mask);
    174 
    175     SOC_IF_ERROR_RETURN
    176         (PHY54618E_CL45_REG_WRITE(unit, pc, flags, dev_addr, reg_addr, value));
    177 
    178     return SOC_E_NONE;
    179 }
    180 
    181 /***********************************************************************
    182  *
    183  * HELPER FUNCTIONS
    184  */
    185 /*
    186  * Function:
    187  *      _phy_54616_medium_check
    188  * Purpose:
    189  *      Determine if chip should operate in copper or fiber mode.
    190  * Parameters:
    191  *      unit - StrataSwitch unit #.
    192  *      port - StrataSwitch port #.
    193  *      medium - (OUT) SOC_PORT_MEDIUM_XXX
    194  * Returns:
    195  *      SOC_E_XXX
    196  */
    197 STATIC int
    198 _phy_54616_medium_check(int unit, soc_port_t port, int *medium)
    199 {
    200     phy_ctrl_t    *pc = EXT_PHY_SW_STATE(unit, port);
    201     uint16         tmp = 0xffff;
    202 
    203     *medium = SOC_PORT_MEDIUM_COPPER;
    204 
    205     if (PHY_PRIMARY_SERDES_MODE(unit, port)) {
    206         /* Ie fiber capable */
    207 
    208         if (pc->automedium) {
    209             /* Read Mode Register (0x1c shadow 11111) */
    210             SOC_IF_ERROR_RETURN
    211                 (READ_PHY54616_MODE_CTRLr(unit, pc, &tmp));
    212 
    213             if (pc->fiber.preferred) {
    214                 /* 0x10 Fiber Signal Detect
    215                  * 0x20 Copper Energy Detect
    216                  */
    217                 if ((tmp & 0x30) == 0x20) {
    218                     /* Only copper is link up */
    219                     *medium = SOC_PORT_MEDIUM_COPPER;
    220                 } else {
    221                     *medium = SOC_PORT_MEDIUM_FIBER;
    222                 }
    223             } else {
    224                 if ((tmp & 0x30) == 0x10) {
    225                     /* Only fiber is link up */
    226                     *medium = SOC_PORT_MEDIUM_FIBER;
    227                 } else {
    228                     *medium = SOC_PORT_MEDIUM_COPPER;
    229                 }
    230             }
    231         } else {
    232             *medium = pc->fiber.preferred ? SOC_PORT_MEDIUM_FIBER:
    233                       SOC_PORT_MEDIUM_COPPER;
    234         } 
    235     }
    236 
    237     LOG_VERBOSE(BSL_LS_SOC_PHY,
    238                 (BSL_META_U(unit,
    239                             "_phy_54616_medium_check: "
    240                             "u=%d p=%d fiber_pref=%d 0x1c(11111)=%04x fiber=%d\n"),
    241                  unit, port, pc->fiber.preferred, tmp, 
    242                  (*medium == SOC_PORT_MEDIUM_FIBER) ? 1 : 0));
    243 
    244     return SOC_E_NONE;
    245 }
    246 
    247 /*
    248  * Function:
    249  *      phy_54616_medium_status
    250  * Purpose:
    251  *      Indicate the current active medium
    252  * Parameters:
    253  *      unit - StrataSwitch unit #.
    254  *      port - StrataSwitch port #.
    255  *      medium - (OUT) One of:
    256  *              SOC_PORT_MEDIUM_COPPER
    257  *              SOC_PORT_MEDIUM_FIBER
    258  * Returns:
    259  *      SOC_E_NONE
    260  */
    261 
    262 STATIC int
    263 phy_54616_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium)
    264 {
    265     if (PHY_COPPER_MODE(unit, port)) {
    266         *medium = SOC_PORT_MEDIUM_COPPER;
    267     } else {
    268         *medium = SOC_PORT_MEDIUM_FIBER;
    269     }
    270     return SOC_E_NONE;
    271 }
    272 
    273 /*
    274  * Function:
    275  *      _phy_54616_medium_config_update
    276  * Purpose:
    277  *      Update the PHY with config parameters
    278  * Parameters:
    279  *      unit - StrataSwitch unit #.
    280  *      port - StrataSwitch port #.
    281  *      cfg - Config structure.
    282  * Returns:
    283  *      SOC_E_XXX
    284  */
    285 
    286 STATIC int
    287 _phy_54616_medium_config_update(int unit, soc_port_t port,
    288                                 soc_phy_config_t *cfg)
    289 {
    290     SOC_IF_ERROR_RETURN
    291         (phy_54616_speed_set(unit, port, cfg->force_speed));
    292     SOC_IF_ERROR_RETURN
    293         (phy_54616_duplex_set(unit, port, cfg->force_duplex));
    294     SOC_IF_ERROR_RETURN
    295         (phy_54616_master_set(unit, port, cfg->master));
    296     SOC_IF_ERROR_RETURN
    297         (phy_54616_ability_advert_set(unit, port, &cfg->advert_ability));
    298     SOC_IF_ERROR_RETURN
    299         (phy_54616_autoneg_set(unit, port, cfg->autoneg_enable));
    300     SOC_IF_ERROR_RETURN
    301         (phy_54616_mdix_set(unit, port, cfg->mdix));
    302 
    303     return SOC_E_NONE;
    304 }
    305 
    306 /***********************************************************************
    307  *
    308  * PHY54616 DRIVER ROUTINES
    309  */
    310 
    311 /*
    312  * Function:
    313  *      phy_54616_medium_config_set
    314  * Purpose:
    315  *      Set the operating parameters that are automatically selected
    316  *      when medium switches type.
    317  * Parameters:
    318  *      unit - StrataSwitch unit #
    319  *      port - Port number
    320  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    321  *      cfg - Operating parameters
    322  * Returns:
    323  *      SOC_E_XXX
    324  */
    325 
    326 STATIC int
    327 phy_54616_medium_config_set(int unit, soc_port_t port, 
    328                            soc_port_medium_t  medium,
    329                            soc_phy_config_t  *cfg)
    330 {
    331     phy_ctrl_t    *pc;
    332     soc_phy_config_t *active_medium;  /* Currently active medium */
    333     soc_phy_config_t *change_medium;  /* Requested medium */
    334     soc_phy_config_t *other_medium;   /* The other medium */
    335     int               medium_update;
    336 
    337     if (NULL == cfg) {
    338         return SOC_E_PARAM;
    339     }
    340 
    341     pc            = EXT_PHY_SW_STATE(unit, port);
    342     medium_update = FALSE;
    343 
    344     switch (medium) {
    345     case SOC_PORT_MEDIUM_COPPER:
    346         if (!pc->automedium) {
    347             if (!PHY_COPPER_MODE(unit, port)) {
    348                 return SOC_E_UNAVAIL;
    349             }
    350             /* check if device is fiber capable before switching */
    351             if (cfg->preferred == 0) {
    352 
    353                 if (!PHY_IS_BCM54616S(pc)) {
    354                     /* return if not fiber capable*/
    355                     return SOC_E_UNAVAIL;
    356                 }
    357             }
    358         }
    359         
    360         change_medium  = &pc->copper;
    361         other_medium   = &pc->fiber;
    362         break;
    363     case SOC_PORT_MEDIUM_FIBER:
    364         if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) {
    365             return SOC_E_UNAVAIL;
    366         }
    367         change_medium  = &pc->fiber;
    368         other_medium   = &pc->copper;
    369         break;
    370     default:
    371         return SOC_E_PARAM;
    372     }
    373 
    374     /*
    375      * Changes take effect immediately if the target medium is active or
    376      * the preferred medium changes.
    377      */
    378     if (change_medium->enable != cfg->enable) {
    379         medium_update = TRUE;
    380     }
    381     if (change_medium->preferred != cfg->preferred) {
    382         /* Make sure that only one medium is preferred */
    383         other_medium->preferred = !cfg->preferred;
    384         medium_update = TRUE;
    385     }
    386 
    387     sal_memcpy(change_medium, cfg, sizeof(*change_medium));
    388 
    389     if (medium_update) {
    390         /* The new configuration may cause medium change. Check
    391          * and update medium.
    392          */
    393         SOC_IF_ERROR_RETURN
    394             (_phy_54616_medium_change(unit, port,TRUE));
    395     } else {
    396         active_medium = (PHY_COPPER_MODE(unit, port)) ?  
    397                             &pc->copper : &pc->fiber;
    398         if (active_medium == change_medium) {
    399             /* If the medium to update is active, update the configuration */
    400             SOC_IF_ERROR_RETURN
    401                 (_phy_54616_medium_config_update(unit, port, change_medium));
    402         }
    403     }
    404     return SOC_E_NONE;
    405 }
    406 
    407 /*
    408  * Function:
    409  *      phy_54616_medium_config_get
    410  * Purpose:
    411  *      Get the operating parameters that are automatically selected
    412  *      when medium switches type.
    413  * Parameters:
    414  *      unit - StrataSwitch unit #
    415  *      port - Port number
    416  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    417  *      cfg - (OUT) Operating parameters
    418  * Returns:
    419  *      SOC_E_XXX
    420  */
    421 
    422 STATIC int
    423 phy_54616_medium_config_get(int unit, soc_port_t port, 
    424                            soc_port_medium_t medium,
    425                            soc_phy_config_t *cfg)
    426 {
    427     int            rv;
    428     phy_ctrl_t    *pc;
    429 
    430     pc = EXT_PHY_SW_STATE(unit, port);
    431     rv = SOC_E_NONE;
    432 
    433     switch (medium) {
    434     case SOC_PORT_MEDIUM_COPPER:
    435         if (pc->automedium || PHY_COPPER_MODE(unit, port)) {
    436             sal_memcpy(cfg, &pc->copper, sizeof (*cfg));
    437         } else {
    438             rv = SOC_E_UNAVAIL;
    439         }
    440         break;
    441     case SOC_PORT_MEDIUM_FIBER:
    442         if (pc->automedium || PHY_FIBER_MODE(unit, port)) {
    443             sal_memcpy(cfg, &pc->fiber, sizeof (*cfg));
    444         } else {
    445             rv = SOC_E_UNAVAIL;
    446         }
    447         break;
    448     default:
    449         rv = SOC_E_PARAM;
    450         break;
    451     }
    452 
    453     return rv;
    454 }
    455 
    456 /*
    457  * Function:
    458  *      _phy_54616_reset_setup
    459  * Purpose:
    460  *      Function to reset the PHY and set up initial operating registers.
    461  * Parameters:
    462  *      unit - StrataSwitch unit #.
    463  *      port - StrataSwitch port #.
    464  * Returns:
    465  *      SOC_E_XXX
    466  * Notes:
    467  *      Configures for copper/fiber according to the current
    468  *      setting of PHY_FLAGS_FIBER.
    469  */
    470 
    471 STATIC int
    472 _phy_54616_reset_setup(int unit, soc_port_t port)
    473 {
    474     phy_ctrl_t    *pc;
    475 
    476     pc = EXT_PHY_SW_STATE(unit, port);
    477 
    478     /* Reset the PHY with previously registered callback function. */
    479     SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port));
    480 
    481     sal_usleep(10000);
    482 
    483     /* Disable super-isolate */
    484     SOC_IF_ERROR_RETURN
    485         (MODIFY_PHY54616_MII_POWER_CTRLr(unit, pc, 0x0, 1U<<5));
    486 
    487     /* BCM54618E/SE is EEE capable */
    488     if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
    489         /* disable AutogrEEEn (default EEE Native node) */
    490         SOC_IF_ERROR_RETURN
    491             (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0000, 0x0001));
    492 
    493         PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE);
    494     }
    495 
    496     SOC_IF_ERROR_RETURN
    497         (_phy_54616_no_reset_setup(unit, port));
    498 
    499     return SOC_E_NONE;
    500 }
    501 
    502 STATIC int
    503 _phy_54616_no_reset_setup(int unit, soc_port_t port)
    504 {
    505     phy_ctrl_t    *int_pc;
    506     phy_ctrl_t    *pc;
    507     uint16         data, mask;
    508 
    509     LOG_INFO(BSL_LS_SOC_PHY,
    510              (BSL_META_U(unit,
    511                          "_phy_54616_reset_setup: u=%d p=%d medium=%s\n"),
    512                          unit, port,
    513               PHY_COPPER_MODE(unit, port) ? "COPPER" : "FIBER"));
    514 
    515     pc      = EXT_PHY_SW_STATE(unit, port);
    516     int_pc  = INT_PHY_SW_STATE(unit, port);
    517 
    518 
    519     /* copper regs */
    520     if (!pc->copper.enable || (!pc->automedium && pc->fiber.preferred)) {
    521         /* Copper interface is not used. Powered down. */
    522         LOG_INFO(BSL_LS_SOC_PHY,
    523                  (BSL_META_U(unit,
    524                              "%s: u=%d p=%d Copper PowerDown=%d!\n"),
    525                              FUNCTION_NAME(), unit, port, 1));
    526         SOC_IF_ERROR_RETURN
    527             (MODIFY_PHY54616_MII_CTRLr(unit, pc, MII_CTRL_PD, MII_CTRL_PD));
    528     } else {
    529         LOG_INFO(BSL_LS_SOC_PHY,
    530                  (BSL_META_U(unit,
    531                              "%s: u=%d p=%d Copper PowerDown=%d!\n"),
    532                              FUNCTION_NAME(), unit, port, 0));
    533         SOC_IF_ERROR_RETURN
    534             (MODIFY_PHY54616_MII_CTRLr(unit, pc, 0, MII_CTRL_PD));
    535         SOC_IF_ERROR_RETURN
    536             (WRITE_PHY54616_MII_GB_CTRLr(unit, pc,
    537                             MII_GB_CTRL_ADV_1000FD | MII_GB_CTRL_PT));
    538         SOC_IF_ERROR_RETURN
    539             (WRITE_PHY54616_MII_CTRLr(unit, pc,
    540                 MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE));
    541     }
    542 
    543     if (NULL != int_pc) {
    544         SOC_IF_ERROR_RETURN
    545             (PHY_INIT(int_pc->pd, unit, port));
    546     }
    547 
    548     /* Configure Auto-detect Medium (0x1c shadow 11110) */
    549     mask = 0x33f;               /* Auto-detect bit mask */
    550 
    551     /* In BCM54616S the SD pin is internally tied. For proper operation
    552        SD_INV and QUALIFY_SD_WITH_SYNC should be set.                  */
    553     data = (1 << 8) | (1 << 5);
    554 
    555     if (pc->automedium) {
    556         data |= 1 << 0;    /* Enable auto-detect medium */
    557     }
    558     /* When no link partner exists, fiber should be default medium */
    559     /* When both link partners exipc, fiber should be prefered medium
    560      * for the following reasons.
    561      * 1. Most fiber module generates signal detect when the fiber cable is
    562      *    plugged in regardless of any activity even if the link partner is
    563      *    powered down.
    564      * 2. Fiber mode consume much lesser power than copper mode.
    565      */
    566     if (pc->fiber.preferred) {
    567         data |= 1 << 1;    /* Fiber selected when both media are active */
    568         data |= 1 << 2;    /* Fiber selected when no medium is active */
    569     }
    570 
    571     SOC_IF_ERROR_RETURN
    572         (MODIFY_PHY54616_AUTO_DETECT_MEDIUMr(unit, pc, data, mask));
    573 
    574 #if DISABLE_CLK125
    575     /* Reduce EMI emissions by disabling the CLK125 pin if not used  */
    576     data = 0x001c;  /* When write, bit 9 and 7 must be zero and */ 
    577     data = 0x029c;  /* bit 2, 3, and 4 must be one. */ 
    578     SOC_IF_ERROR_RETURN
    579         (MODIFY_PHY54616_SPARE_CTRL_3r(unit, pc, 0, 1));
    580 #endif
    581 
    582 #if AUTO_MDIX_WHEN_AN_DIS
    583     /* Enable Auto-MDIX When autoneg disabled */
    584     SOC_IF_ERROR_RETURN
    585         (MODIFY_PHY54616_MII_MISC_CTRLr(unit, pc, 0x200, 0x200));
    586 #endif
    587     /*
    588      * Configure Auxiliary 1000BASE-X control register to turn off
    589      * carrier extension.  The Intel 7131 NIC does not accept carrier
    590      * extension and gets CRC errors.
    591      */
    592     SOC_IF_ERROR_RETURN
    593         (MODIFY_PHY54616_AUX_1000X_CTRLr(unit, pc, 0x0040, 0x0040));
    594     /* Enable LPI pass through on PHY for native EEE */ /*
    595     if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
    596         SOC_IF_ERROR_RETURN   
    597             (phy_reg_aer_modify(unit, pc, 0x833e, 0xc000, 0xc000));
    598     }
    599     */
    600 
    601     /* Configure extended control register for led mode and jumbo frame support */
    602     mask  = (1 << 5) | (1 << 0);
    603 
    604     /* if using led link/activity mode, disable led traffic mode */
    605     if (pc->ledctrl & 0x10 || pc->ledselect == 0x01) {
    606         data = 0;
    607     } else {
    608         data  = 1 << 5;      /* Enable LEDs to indicate traffic status */
    609     }
    610     /* Configure Extended Control Register for Jumbo frames support */
    611     data |= 1 << 0;      /* Set high FIFO elasticity to support jumbo frames */
    612     SOC_IF_ERROR_RETURN
    613         (MODIFY_PHY54616_MII_ECRr(unit, pc, data, mask));
    614     /* Enable extended packet length (4.5k through 25k) */
    615     SOC_IF_ERROR_RETURN
    616         (MODIFY_PHY54616_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000));
    617     /* 1000BASE-T PCS Transmit FIFO Elasticity          *\
    618     \* enable jumbo frame for SGMII-Copper or GBIC mode */
    619     SOC_IF_ERROR_RETURN
    620         (MODIFY_PHY54616_AUTO_DETECT_SGMII_MEDIAr(unit, pc, 0x4, 0x4));
    621 
    622     /* Configure LED selectors */
    623     data = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf);
    624     SOC_IF_ERROR_RETURN
    625         (WRITE_PHY54616_LED_SELECTOR_1r(unit, pc, data));
    626 
    627     data = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf);
    628     SOC_IF_ERROR_RETURN
    629         (WRITE_PHY54616_LED_SELECTOR_2r(unit, pc, data));
    630 
    631     data = (pc->ledctrl & 0x3ff);
    632     SOC_IF_ERROR_RETURN
    633         (WRITE_PHY54616_LED_CTRLr(unit, pc, data));
    634 
    635     SOC_IF_ERROR_RETURN
    636         (WRITE_PHY54616_EXP_LED_SELECTORr(unit, pc, pc->ledselect));
    637 
    638     /*
    639     if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
    640         return SOC_E_NONE;
    641     }
    642     */
    643 
    644     /* 100BASE-TX initialization change for EEE and autogreen mode */
    645     /*
    646     SOC_IF_ERROR_RETURN
    647         (MODIFY_PHY54618_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00));
    648     SOC_IF_ERROR_RETURN(
    649         WRITE_PHY_REG(unit, pc, 0x17, 0x4022));
    650     SOC_IF_ERROR_RETURN(
    651         WRITE_PHY_REG(unit, pc, 0x15, 0x017b));
    652     SOC_IF_ERROR_RETURN
    653         (MODIFY_PHY54618_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00));
    654     */
    655 
    656    return SOC_E_NONE;
    657 }
    658 
    659 /*
    660  * Function:
    661  *      phy_54616_init
    662  * Purpose:
    663  *      Init function for 54616 PHY.
    664  * Parameters:
    665  *      unit - StrataSwitch unit #.
    666  *      port - StrataSwitch port #.
    667  * Returns:
    668  *      SOC_E_NONE
    669  */
    670 
    671 STATIC int
    672 phy_54616_init(int unit, soc_port_t port)
    673 {
    674     phy_ctrl_t *pc;
    675     int        fiber_capable;
    676     int        fiber_preferred;
    677     uint16     data;
    678 
    679     LOG_INFO(BSL_LS_SOC_PHY,
    680              (BSL_META_U(unit,
    681                          "phy_54616_init: u=%d p=%d\n"),
    682                          unit, port));
    683 
    684     pc = EXT_PHY_SW_STATE(unit, port);
    685 
    686     if ( PHY_IS_BCM54616S(pc) ) {
    687         /* check the for the precense of the SERDES block and and read
    688           the INTF_SEL[1:0] strap values */
    689 
    690         SOC_IF_ERROR_RETURN
    691             (READ_PHY54616_MODE_CTRLr(unit, pc, &data));
    692 
    693         if ((data & (0x2 << 1)) == (0x2 << 1)) {
    694             pc->interface = SOC_PORT_IF_SGMII;
    695             fiber_capable = FALSE;
    696         } else {
    697             /* pc->interface = SOC_PORT_IF_RGMII; */
    698             pc->interface = SOC_PORT_IF_GMII; /* MAC unable to handle SOC_PORT_IF_RGMII */
    699             PHY_FLAGS_SET(pc->unit, pc->port, PHY_FLAGS_PRIMARY_SERDES);
    700             fiber_capable = TRUE;
    701         }
    702     } else {
    703         pc->interface = SOC_PORT_IF_GMII;
    704         fiber_capable = FALSE;
    705     }
    706 
    707     /*
    708      * In automedium mode, the property phy_fiber_pref_port<X> is used
    709      * to set a preference for fiber mode in the event both copper and
    710      * fiber links are up.
    711      *
    712      * If NOT in automedium mode, phy_fiber_pref_port<X> is used to
    713      * select which of fiber or copper is forced.
    714      */
    715     if (!fiber_capable) {
    716         fiber_preferred = 0;
    717         pc->automedium      = 0;
    718     } else {
    719         fiber_preferred =
    720             soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 1);
    721         pc->automedium =
    722             soc_property_port_get(unit, port, spn_PHY_AUTOMEDIUM, 1);
    723     }
    724 
    725     LOG_INFO(BSL_LS_SOC_PHY,
    726              (BSL_META_U(unit,
    727                          "phy_54616_init: "
    728                          "u=%d p=%d type=54616%s automedium=%d fiber_pref=%d\n"),
    729               unit, port, fiber_capable ? "S" : "",
    730               pc->automedium, fiber_preferred));
    731 
    732     pc->copper.enable = TRUE;
    733     pc->copper.preferred = !fiber_preferred;
    734     pc->copper.autoneg_enable = TRUE;
    735     pc->copper.force_speed = 1000;
    736     pc->copper.force_duplex = TRUE;
    737     pc->copper.master = SOC_PORT_MS_AUTO;
    738     pc->copper.mdix = SOC_PORT_MDIX_AUTO;
    739 
    740     pc->fiber.enable = fiber_capable;
    741     pc->fiber.preferred = fiber_preferred;
    742     pc->fiber.autoneg_enable = fiber_capable;
    743     pc->fiber.force_speed = 1000;
    744     pc->fiber.force_duplex = TRUE;
    745     pc->fiber.master = SOC_PORT_MS_NONE;
    746     pc->fiber.mdix = SOC_PORT_MDIX_NORMAL;
    747 
    748     SOC_IF_ERROR_RETURN
    749         (_phy_54616_copper_ability_local_get(unit, port, &pc->copper.advert_ability));
    750     if (fiber_capable) {
    751         (_phy_54616_fiber_ability_local_get(unit, port, &pc->fiber.advert_ability));
    752     }
    753 
    754     /* Initially configure for the preferred medium. */
    755     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER);
    756     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
    757     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU);
    758     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
    759     PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
    760     PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE);
    761 
    762     if (pc->fiber.preferred) {
    763         PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
    764     } else {
    765         PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER);
    766     }
    767 
    768     /* Get Requested LED selectors (defaults are hardware defaults) */
    769     pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0);
    770     pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1);
    771     pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3);
    772     pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6);
    773     pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8);
    774     pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0);
    775 
    776     SOC_IF_ERROR_RETURN
    777         (_phy_54616_reset_setup(unit, port));
    778 
    779     SOC_IF_ERROR_RETURN
    780         (_phy_54616_medium_config_update(unit, port,
    781                                         PHY_COPPER_MODE(unit, port) ?
    782                                         &pc->copper :
    783                                         &pc->fiber));
    784     return SOC_E_NONE;
    785 }
    786 
    787 /*
    788  * Function:
    789  *      phy_54616_enable_set
    790  * Purpose:
    791  *      Enable or disable the physical interface.
    792  * Parameters:
    793  *      unit - StrataSwitch unit #.
    794  *      port - StrataSwitch port #.
    795  *      enable - Boolean, true = enable PHY, false = disable.
    796  * Returns:
    797  *      SOC_E_XXX
    798  */
    799 
    800 STATIC int
    801 phy_54616_enable_set(int unit, soc_port_t port, int enable)
    802 {
    803     uint16         power;
    804     phy_ctrl_t    *pc;
    805 
    806     pc     = EXT_PHY_SW_STATE(unit, port);
    807     power  = (enable) ? 0 : MII_CTRL_PD;
    808 
    809     /* Do not incorrectly Power up the interface if medium is disabled and 
    810      * global enable = true
    811      */
    812     if (pc->copper.enable && (pc->automedium || PHY_COPPER_MODE(unit, port))) {
    813         SOC_IF_ERROR_RETURN
    814             (MODIFY_PHY54616_MII_CTRLr(unit, pc, power, MII_CTRL_PD));
    815 
    816         LOG_INFO(BSL_LS_SOC_PHY,
    817                  (BSL_META_U(unit,
    818                              "phy_54616_enable_set: "
    819                              "Power %s copper medium\n"), (enable) ? "up" : "down"));
    820     }
    821 
    822     if (pc->fiber.enable && (pc->automedium || PHY_FIBER_MODE(unit, port))) {
    823         SOC_IF_ERROR_RETURN
    824             (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, power, 
    825                                                    MII_CTRL_PD));
    826 
    827         LOG_INFO(BSL_LS_SOC_PHY,
    828                  (BSL_META_U(unit,
    829                              "phy_54616_enable_set: "
    830                              "Power %s fiber medium\n"), (enable) ? "up" : "down"));
    831     }
    832 
    833     /* Update software state */
    834     SOC_IF_ERROR_RETURN(phy_fe_ge_enable_set(unit, port, enable));
    835 
    836     return SOC_E_NONE;
    837 }
    838 
    839 /*
    840  * Function:
    841  *      phy_54616_enable_get
    842  * Purpose:
    843  *      Enable or disable the physical interface for a 54616 device.
    844  * Parameters:
    845  *      unit - StrataSwitch unit #.
    846  *      port - StrataSwitch port #.
    847  *      enable - (OUT) Boolean, true = enable PHY, false = disable.
    848  * Returns:
    849  *      SOC_E_XXX
    850  */
    851 
    852 STATIC int
    853 phy_54616_enable_get(int unit, soc_port_t port, int *enable)
    854 {
    855     return phy_fe_ge_enable_get(unit, port, enable);
    856 }
    857 
    858 /*
    859  * Function:
    860  *      _phy_54616_100fx_setup
    861  * Purpose:
    862  *      Switch from 1000X mode to 100FX.  
    863  * Parameters:
    864  *      unit - StrataSwitch unit #.
    865  *      port - StrataSwitch port #.
    866  * Returns:
    867  *      SOC_E_XXX
    868  */
    869 STATIC int
    870 _phy_54616_fiber_100fx_setup(int unit, soc_port_t port) 
    871 {
    872     phy_ctrl_t    *pc;
    873     uint16        data;
    874 
    875     pc          = EXT_PHY_SW_STATE(unit, port);
    876 
    877     LOG_VERBOSE(BSL_LS_SOC_PHY,
    878                 (BSL_META_U(unit,
    879                             "_phy_54616_1000x_to_100fx: u=%d p=%d \n"),
    880                  unit, port));
    881 
    882     /* clear the power down bit of the SerDes */
    883     LOG_INFO(BSL_LS_SOC_PHY,
    884              (BSL_META_U(unit,
    885                          "%s:p=%d,Pri-SerDes mode. Fiber PowerDown(%s)!\n"),
    886               FUNCTION_NAME(), port, "No"));
    887     SOC_IF_ERROR_RETURN(
    888         MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, 0, MII_CTRL_PD));
    889 
    890     /* set to fiber mode */ /* bit[2:1]=1 */
    891     SOC_IF_ERROR_RETURN(
    892         MODIFY_PHY54616_MODE_CTRLr(unit, pc, 0x2,0x6));
    893 
    894     /* set loopback */
    895     SOC_IF_ERROR_RETURN(
    896         MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, MII_CTRL_LE, MII_CTRL_LE));
    897 
    898     /* select 100FX mode */
    899         /* bit[0]=1 */
    900     data = 1;
    901     data |= pc->fiber.force_duplex? PHY_54616_PRIMARY_SERDES_100FX_FD:0;
    902 
    903     SOC_IF_ERROR_RETURN(
    904         MODIFY_PHY54616_100FX_CTRLr(unit, pc, data,
    905           1 | PHY_54616_PRIMARY_SERDES_100FX_FD));
    906 
    907     /* Power down SerDes RX path (Expention register)*/
    908     /* Power up SerDes RX path */ /* select Exp_reg 05 */
    909     SOC_IF_ERROR_RETURN(
    910         WRITE_PHY54616_EXP_LED_FLASH_CTRLr(unit, pc, 0x0C3B));
    911     SOC_IF_ERROR_RETURN(
    912         WRITE_PHY54616_EXP_LED_FLASH_CTRLr(unit, pc, 0x0C3A));
    913 
    914     /* reset loopback to switch clock back to SerDes RX clock */
    915         /* bit[14]=0 */
    916     SOC_IF_ERROR_RETURN(
    917         MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc,
    918             PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE) ? MII_CTRL_PD : 0,
    919             MII_CTRL_LE | MII_CTRL_PD));
    920 
    921     PHY_FLAGS_SET(unit, port, PHY_FLAGS_100FX);
    922     pc->fiber.force_speed    = 100;
    923     pc->fiber.autoneg_enable = FALSE;
    924 
    925     return SOC_E_NONE;
    926 }
    927 
    928 /*
    929  * Function:
    930  *      _phy_54616_1000x_setup
    931  * Purpose:
    932  *      Switch from 100FX mode to 1000X.  
    933  * Parameters:
    934  *      unit - StrataSwitch unit #.
    935  *      port - StrataSwitch port #.
    936  * Returns:
    937  *      SOC_E_XXX
    938  */
    939 STATIC int
    940 _phy_54616_fiber_1000x_setup(int unit, soc_port_t port) 
    941 {
    942     phy_ctrl_t    *pc;
    943 
    944     pc          = EXT_PHY_SW_STATE(unit, port);
    945 
    946     LOG_VERBOSE(BSL_LS_SOC_PHY,
    947                 (BSL_META_U(unit,
    948                             "_phy_54616_fiber_1000x_setup: u=%d p=%d \n"),
    949                  unit, port));
    950 
    951     /* set to Fiber mode and enable primary SerDes register */
    952         /* bit[2:1]=01*/
    953     SOC_IF_ERROR_RETURN(
    954         MODIFY_PHY54616_MODE_CTRLr(unit, pc, 0x2,0x6));
    955     /* enable 1000X, ie. disable 100FX */
    956         /* bit[0]=0 */
    957     SOC_IF_ERROR_RETURN(
    958         MODIFY_PHY54616_100FX_CTRLr(unit,pc, 0, 1));
    959 
    960     /* clear the SerDes power down bit */
    961         /* bit[11]=0 */
    962     LOG_INFO(BSL_LS_SOC_PHY,
    963              (BSL_META_U(unit,
    964                          "%s:p=%d,Pri-SerDes Mode. Fiber PowerDown(%s)!\n"),
    965               FUNCTION_NAME(), port, "No"));
    966     SOC_IF_ERROR_RETURN(
    967         MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc,
    968             PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE) ? MII_CTRL_PD : 0,
    969             MII_CTRL_PD));
    970  
    971     pc->fiber.force_duplex = TRUE;
    972     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
    973 
    974     return SOC_E_NONE;
    975 }
    976 
    977 STATIC int
    978 _phy_54616_medium_change(int unit, soc_port_t port, int force_update)
    979 {
    980     phy_ctrl_t    *pc;
    981     int            medium;
    982 
    983     pc    = EXT_PHY_SW_STATE(unit, port);
    984 
    985     SOC_IF_ERROR_RETURN
    986         (_phy_54616_medium_check(unit, port, &medium));
    987 
    988     if (medium == SOC_PORT_MEDIUM_COPPER) {
    989         if ((!PHY_COPPER_MODE(unit, port)) || force_update) { /* Was fiber */ 
    990             PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER);
    991             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
    992             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
    993             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
    994             /* BCM54618E/SE is EEE capable */
    995             if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
    996                 PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE);
    997             }
    998             SOC_IF_ERROR_RETURN
    999                 (_phy_54616_no_reset_setup(unit, port));
   1000 
   1001             /* Do not power up the interface if medium is disabled. */
   1002             if (pc->copper.enable) {
   1003                 SOC_IF_ERROR_RETURN
   1004                     (_phy_54616_medium_config_update(unit, port, &pc->copper));
   1005             }
   1006             LOG_INFO(BSL_LS_SOC_PHY,
   1007                      (BSL_META_U(unit,
   1008                                  "_phy_54616_link_auto_detect: u=%d p=%d [F->C]\n"),
   1009                       unit, port));
   1010         }
   1011     } else {        /* Fiber */
   1012         if (PHY_COPPER_MODE(unit, port) || force_update) { /* Was copper */
   1013             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER);
   1014             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_EEE_CAPABLE);
   1015             PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
   1016             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1017             SOC_IF_ERROR_RETURN
   1018                 (_phy_54616_no_reset_setup(unit, port));
   1019 
   1020             if (pc->fiber.enable) {
   1021                 SOC_IF_ERROR_RETURN
   1022                     (_phy_54616_medium_config_update(unit, port, &pc->fiber));
   1023             }
   1024             LOG_INFO(BSL_LS_SOC_PHY,
   1025                      (BSL_META_U(unit,
   1026                                  "_phy_54616_link_auto_detect: u=%d p=%d [C->F]\n"),
   1027                       unit, port));
   1028         }
   1029     }
   1030     return SOC_E_NONE;
   1031 }
   1032 
   1033 /*
   1034  * Function:
   1035  *      phy_54616_link_get
   1036  * Purpose:
   1037  *      Determine the current link up/down status for a 54616 device.
   1038  * Parameters:
   1039  *      unit - StrataSwitch unit #.
   1040  *      port - StrataSwitch port #.
   1041  *      link - (OUT) Boolean, true indicates link established.
   1042  * Returns:
   1043  *      SOC_E_XXX
   1044  * Notes:
   1045  *      If using automedium, also switches the mode.
   1046  */
   1047 STATIC int
   1048 phy_54616_link_get(int unit, soc_port_t port, int *link)
   1049 {
   1050     phy_ctrl_t    *pc;
   1051     uint16         data; 
   1052     uint16         mask;
   1053 
   1054     pc    = EXT_PHY_SW_STATE(unit, port);
   1055     *link = FALSE;      /* Default return */
   1056 
   1057     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
   1058         return SOC_E_NONE;
   1059     }
   1060 
   1061     if (!pc->fiber.enable && !pc->copper.enable) {
   1062         return SOC_E_NONE;
   1063     }
   1064 
   1065     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1066     if (pc->automedium) {
   1067         /* Check for medium change and update HW/SW accordingly. */
   1068         SOC_IF_ERROR_RETURN
   1069             (_phy_54616_medium_change(unit, port,FALSE));
   1070     }
   1071     if (PHY_COPPER_MODE(unit, port)) {
   1072         SOC_IF_ERROR_RETURN(phy_fe_ge_link_get(unit, port, link));
   1073     } else {
   1074         SOC_IF_ERROR_RETURN
   1075             (READ_PHY54616_1000X_MII_STATr(unit, pc, &data));
   1076         *link = (data & MII_STAT_LA) ? TRUE : FALSE;
   1077     }
   1078 
   1079     /* If preferred medium is up, disable the other medium 
   1080      * to prevent false link. */
   1081     if (pc->automedium) {
   1082         mask = MII_CTRL_PD;
   1083         if (pc->copper.preferred) {
   1084             if (pc->fiber.enable) {
   1085                 /* power down secondary serdes */
   1086                 data = (*link && PHY_COPPER_MODE(unit, port)) ? MII_CTRL_PD : 0;
   1087             } else {
   1088                 data = MII_CTRL_PD;
   1089             }
   1090             SOC_IF_ERROR_RETURN
   1091                 (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, data, mask));
   1092         } else {  /* pc->fiber.preferred */
   1093             if (pc->copper.enable) {
   1094                 data = (*link && PHY_FIBER_MODE(unit, port)) ? MII_CTRL_PD : 0;
   1095             } else {
   1096                 data = MII_CTRL_PD;
   1097             }
   1098             SOC_IF_ERROR_RETURN
   1099                 (MODIFY_PHY54616_MII_CTRLr(unit, pc, data, mask));
   1100         }
   1101     }
   1102 
   1103     LOG_VERBOSE(BSL_LS_SOC_PHY,
   1104                 (BSL_META_U(unit,
   1105                             "phy_54616_link_get: u=%d p=%d mode=%s%s link=%d\n"),
   1106                  unit, port,
   1107                  PHY_COPPER_MODE(unit, port) ? "C" : "F",
   1108                  PHY_FIBER_100FX_MODE(unit, port)? "(100FX)" : "",
   1109                  *link));
   1110 
   1111     return SOC_E_NONE;
   1112 }
   1113 
   1114 /*
   1115  * Function:
   1116  *      phy_54616_duplex_set
   1117  * Purpose:
   1118  *      Set the current duplex mode (forced).
   1119  * Parameters:
   1120  *      unit - StrataSwitch unit #.
   1121  *      port - StrataSwitch port #.
   1122  *      duplex - Boolean, true indicates full duplex, false indicates half.
   1123  * Returns:
   1124  *      SOC_E_NONE
   1125  *      SOC_E_UNAVAIL - Half duplex requested, and not supported.
   1126  * Notes:
   1127  *      The duplex is set only for the ACTIVE medium.
   1128  *      No synchronization performed at this level.
   1129  *      Autonegotiation is not manipulated.
   1130  */
   1131 
   1132 STATIC int
   1133 phy_54616_duplex_set(int unit, soc_port_t port, int duplex)
   1134 {
   1135     int                  rv;
   1136     phy_ctrl_t    *pc;
   1137 
   1138     pc = EXT_PHY_SW_STATE(unit, port);
   1139     rv = SOC_E_NONE;
   1140     if (PHY_COPPER_MODE(unit, port)) {
   1141         rv = phy_fe_ge_duplex_set(unit, port, duplex);
   1142         if (SOC_SUCCESS(rv)) {
   1143             pc->copper.force_duplex = duplex;
   1144         }
   1145     } else {    /* Fiber */
   1146         if (PHY_FIBER_100FX_MODE(unit, port)) {
   1147             SOC_IF_ERROR_RETURN
   1148                 (MODIFY_PHY54616_100FX_CTRLr(unit, pc,
   1149                        duplex? PHY_54616_PRIMARY_SERDES_100FX_FD:0, PHY_54616_PRIMARY_SERDES_100FX_FD));
   1150             pc->fiber.force_duplex = duplex;
   1151         } else { /* 1000X always full duplex */
   1152             if (!duplex) {
   1153                 rv = SOC_E_UNAVAIL;
   1154             }
   1155         }
   1156     }
   1157     LOG_INFO(BSL_LS_SOC_PHY,
   1158              (BSL_META_U(unit,
   1159                          "phy_54616_duplex_set: u=%d p=%d d=%d rv=%d\n"),
   1160               unit, port, duplex, rv));
   1161 
   1162     return rv;
   1163 }
   1164 
   1165 /*
   1166  * Function:
   1167  *      phy_54616_duplex_get
   1168  * Purpose:
   1169  *      Get the current operating duplex mode. If autoneg is enabled,
   1170  *      then operating mode is returned, otherwise forced mode is returned.
   1171  * Parameters:
   1172  *      unit - StrataSwitch unit #.
   1173  *      port - StrataSwitch port #.
   1174  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1175  *              indicates half.
   1176  * Returns:
   1177  *      SOC_E_NONE
   1178  * Notes:
   1179  *      The duplex is retrieved for the ACTIVE medium.
   1180  *      No synchronization performed at this level. Autonegotiation is
   1181  *      not manipulated.
   1182  */
   1183 
   1184 STATIC int
   1185 phy_54616_duplex_get(int unit, soc_port_t port, int *duplex)
   1186 {
   1187     phy_ctrl_t    *pc;
   1188     uint16 data16;
   1189 
   1190     pc = EXT_PHY_SW_STATE(unit, port);
   1191 
   1192     if (PHY_COPPER_MODE(unit, port)) {
   1193         return phy_fe_ge_duplex_get(unit, port, duplex);    
   1194     } else {
   1195         if (PHY_FIBER_100FX_MODE(unit, port)) {
   1196             SOC_IF_ERROR_RETURN
   1197                 (READ_PHY54616_100FX_CTRLr(unit, pc, &data16));
   1198             *duplex = (data16 & PHY_54616_PRIMARY_SERDES_100FX_FD) ?
   1199                       TRUE: FALSE;
   1200         } else { /* 1000X */ 
   1201             *duplex = TRUE;
   1202         }
   1203     }
   1204         
   1205     return SOC_E_NONE;
   1206 }
   1207 
   1208 /*
   1209  * Function:
   1210  *      phy_54616_speed_set
   1211  * Purpose:
   1212  *      Set the current operating speed (forced).
   1213  * Parameters:
   1214  *      unit - StrataSwitch unit #.
   1215  *      port - StrataSwitch port #.
   1216  *      speed - Requested speed, only 1000 supported.
   1217  * Returns:
   1218  *      SOC_E_XXX
   1219  * Notes:
   1220  *      The speed is set only for the ACTIVE medium.
   1221  */
   1222 
   1223 STATIC int
   1224 phy_54616_speed_set(int unit, soc_port_t port, int speed)
   1225 {
   1226     int            rv; 
   1227     phy_ctrl_t    *pc;
   1228 
   1229     pc = EXT_PHY_SW_STATE(unit, port);
   1230     rv = SOC_E_NONE;
   1231     if (PHY_COPPER_MODE(unit, port)) {
   1232         /* Note: mac.c uses phy_5690_notify_speed to update 5690 */
   1233         rv = phy_fe_ge_speed_set(unit, port, speed);
   1234         if (SOC_SUCCESS(rv)) {
   1235             pc->copper.force_speed = speed;
   1236         }
   1237     } else {    /* Fiber */
   1238         if (speed == 100) {
   1239             rv = _phy_54616_fiber_100fx_setup(unit, port);
   1240        } else  if (speed == 0 || speed == 1000) {
   1241             rv = _phy_54616_fiber_1000x_setup(unit, port);
   1242        } else {
   1243             rv = SOC_E_CONFIG;
   1244        }
   1245        if (SOC_SUCCESS(rv)) {
   1246            pc->fiber.force_speed = speed;
   1247        }
   1248     }
   1249     if (SOC_SUCCESS(rv) && !PHY_SGMII_AUTONEG_MODE(unit, port)) {
   1250         uint16 mii_ctrl;
   1251 
   1252         SOC_IF_ERROR_RETURN
   1253             (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &mii_ctrl));
   1254 
   1255         mii_ctrl &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB);
   1256         switch(speed) {
   1257         case 10:
   1258             mii_ctrl |= MII_CTRL_SS_10;
   1259             break;
   1260         case 100:
   1261             mii_ctrl |= MII_CTRL_SS_100;
   1262             break;
   1263         case 0: 
   1264         case 1000:
   1265             mii_ctrl |= MII_CTRL_SS_1000;
   1266             break;
   1267         default:
   1268             return(SOC_E_CONFIG);
   1269         }
   1270 
   1271         SOC_IF_ERROR_RETURN
   1272             (WRITE_PHY54616_1000X_MII_CTRLr(unit, pc, mii_ctrl));
   1273     }
   1274 
   1275     LOG_INFO(BSL_LS_SOC_PHY,
   1276              (BSL_META_U(unit,
   1277                          "phy_54616_speed_set: u=%d p=%d s=%d fiber=%d rv=%d\n"),
   1278               unit, port, speed, PHY_FIBER_MODE(unit, port), rv));
   1279 
   1280     return rv;
   1281 }
   1282 
   1283 /*
   1284  * Function:
   1285  *      phy_54616_speed_get
   1286  * Purpose:
   1287  *      Get the current operating speed for a 54616 device.
   1288  * Parameters:
   1289  *      unit - StrataSwitch unit #.
   1290  *      port - StrataSwitch port #.
   1291  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1292  *              indicates half.
   1293  * Returns:
   1294  *      SOC_E_NONE
   1295  * Notes:
   1296  *      The speed is retrieved for the ACTIVE medium.
   1297  */
   1298 
   1299 STATIC int
   1300 phy_54616_speed_get(int unit, soc_port_t port, int *speed)
   1301 {
   1302     phy_ctrl_t    *pc;
   1303     uint16         opt_mode;
   1304 
   1305     pc = EXT_PHY_SW_STATE(unit, port);
   1306 
   1307     if (PHY_COPPER_MODE(unit, port)) {
   1308         return phy_fe_ge_speed_get(unit, port, speed);
   1309     } else {
   1310         *speed = 1000;
   1311         SOC_IF_ERROR_RETURN
   1312             (READ_PHY54616_EXP_OPT_MODE_STATr(unit, pc, &opt_mode));
   1313         switch(opt_mode & (0x3 << 13)) {
   1314         case (0 << 13):
   1315             *speed = 10;
   1316             break;
   1317         case (1 << 13):
   1318             *speed = 100;
   1319             break;
   1320         case (2 << 13):
   1321             *speed = 1000;
   1322             break;
   1323         default:
   1324             LOG_WARN(BSL_LS_SOC_PHY,
   1325                      (BSL_META_U(unit,
   1326                                  "phy_54616_speed_get: u=%d p=%d invalid speed\n"),
   1327                       unit, port));
   1328         }
   1329     }
   1330 
   1331     return SOC_E_NONE;
   1332 }
   1333 
   1334 /*
   1335  * Function:
   1336  *      phy_54616_master_set
   1337  * Purpose:
   1338  *      Set the current master mode
   1339  * Parameters:
   1340  *      unit - StrataSwitch unit #.
   1341  *      port - StrataSwitch port #.
   1342  *      master - SOC_PORT_MS_*
   1343  * Returns:
   1344  *      SOC_E_XXX
   1345  * Notes:
   1346  *      The master mode is set only for the ACTIVE medium.
   1347  */
   1348 STATIC int
   1349 phy_54616_master_set(int unit, soc_port_t port, int master)
   1350 {
   1351     int                  rv;
   1352     phy_ctrl_t    *pc;
   1353 
   1354     pc = EXT_PHY_SW_STATE(unit, port);
   1355     rv = SOC_E_NONE;
   1356     if (PHY_COPPER_MODE(unit, port)) {
   1357         rv = phy_fe_ge_master_set(unit, port, master);
   1358         if (SOC_SUCCESS(rv)) {
   1359             pc->copper.master = master;
   1360         }
   1361     }
   1362     LOG_INFO(BSL_LS_SOC_PHY,
   1363              (BSL_META_U(unit,
   1364                          "phy_54616_master_set: u=%d p=%d master=%d fiber=%d rv=%d\n"),
   1365               unit, port, master, PHY_FIBER_MODE(unit, port), rv));
   1366     return rv;
   1367 }
   1368 
   1369 /*
   1370  * Function:
   1371  *      phy_54616_master_get
   1372  * Purpose:
   1373  *      Get the current master mode for a 54616 device.
   1374  * Parameters:
   1375  *      unit - StrataSwitch unit #.
   1376  *      port - StrataSwitch port #.
   1377  *      master - (OUT) SOC_PORT_MS_*
   1378  * Returns:
   1379  *      SOC_E_NONE
   1380  * Notes:
   1381  *      The master mode is retrieved for the ACTIVE medium.
   1382  */
   1383 
   1384 STATIC int
   1385 phy_54616_master_get(int unit, soc_port_t port, int *master)
   1386 {
   1387     if (PHY_COPPER_MODE(unit, port)) {
   1388         return phy_fe_ge_master_get(unit, port, master);
   1389     } else {
   1390         *master = SOC_PORT_MS_NONE;
   1391         return SOC_E_NONE;
   1392     }
   1393 }
   1394 
   1395 /*
   1396  * Function:
   1397  *      phy_54616_autoneg_set
   1398  * Purpose:
   1399  *      Enable or disable auto-negotiation on the specified port.
   1400  * Parameters:
   1401  *      unit - StrataSwitch unit #.
   1402  *      port - StrataSwitch port #.
   1403  *      autoneg - Boolean, if true, auto-negotiation is enabled
   1404  *              (and/or restarted). If false, autonegotiation is disabled.
   1405  * Returns:
   1406  *      SOC_E_XXX
   1407  * Notes:
   1408  *      The autoneg mode is set only for the ACTIVE medium.
   1409  */
   1410 
   1411 STATIC int
   1412 phy_54616_autoneg_set(int unit, soc_port_t port, int autoneg)
   1413 {
   1414     int                 rv;
   1415     uint16              data, mask;
   1416     phy_ctrl_t   *pc;
   1417 
   1418     /* don't allow AN if port is disabled  */
   1419 
   1420     if (autoneg) {
   1421         if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
   1422             return SOC_E_NONE;
   1423         }
   1424     }
   1425 
   1426     pc = EXT_PHY_SW_STATE(unit, port);
   1427     rv = SOC_E_NONE;
   1428     if (PHY_COPPER_MODE(unit, port)) {
   1429         rv = phy_fe_ge_an_set(unit, port, autoneg);
   1430         if (SOC_SUCCESS(rv)) {
   1431             pc->copper.autoneg_enable = autoneg ? 1 : 0;
   1432         }
   1433     } else { 
   1434         data = (autoneg) ? MII_CTRL_AE | MII_CTRL_RAN : 0;
   1435         mask = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD;
   1436         SOC_IF_ERROR_RETURN
   1437             (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, data, mask));
   1438 
   1439         pc->fiber.autoneg_enable = autoneg ? TRUE : FALSE;
   1440     }
   1441  
   1442     LOG_INFO(BSL_LS_SOC_PHY,
   1443              (BSL_META_U(unit,
   1444                          "phy_54616_autoneg_set: u=%d p=%d autoneg=%d rv=%d\n"),
   1445               unit, port, autoneg, rv));
   1446 
   1447     return rv;
   1448 }
   1449 
   1450 /*
   1451  * Function:
   1452  *      phy_54616_autoneg_get
   1453  * Purpose:
   1454  *      Get the current auto-negotiation status (enabled/busy).
   1455  * Parameters:
   1456  *      unit - StrataSwitch unit #.
   1457  *      port - StrataSwitch port #.
   1458  *      autoneg - (OUT) if true, auto-negotiation is enabled.
   1459  *      autoneg_done - (OUT) if true, auto-negotiation is complete. This
   1460  *              value is undefined if autoneg == FALSE.
   1461  * Returns:
   1462  *      SOC_E_XXX
   1463  * Notes:
   1464  *      The autoneg mode is retrieved for the ACTIVE medium.
   1465  */
   1466 
   1467 STATIC int
   1468 phy_54616_autoneg_get(int unit, soc_port_t port,
   1469                      int *autoneg, int *autoneg_done)
   1470 {
   1471     int           rv;
   1472     uint16        data;
   1473     phy_ctrl_t   *pc;
   1474 
   1475     pc = EXT_PHY_SW_STATE(unit, port);
   1476 
   1477     rv            = SOC_E_NONE;
   1478     *autoneg      = FALSE;
   1479     *autoneg_done = FALSE;
   1480     if (PHY_COPPER_MODE(unit, port)) {
   1481         rv = phy_fe_ge_an_get(unit, port, autoneg, autoneg_done);
   1482     } else {
   1483         /* autoneg is not enabled in 100FX mode */
   1484         if (PHY_FIBER_100FX_MODE(unit, port)) {
   1485             *autoneg = FALSE;
   1486             *autoneg_done = TRUE;
   1487             return rv;
   1488         }
   1489         SOC_IF_ERROR_RETURN
   1490             (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &data));
   1491         if (data & MII_CTRL_AE) {
   1492             *autoneg = TRUE;
   1493 
   1494             SOC_IF_ERROR_RETURN
   1495                 (READ_PHY54616_1000X_MII_STATr(unit, pc, &data));
   1496             if (data & MII_STAT_AN_DONE) {
   1497                 *autoneg_done = TRUE;
   1498             }
   1499         }
   1500         
   1501     }
   1502 
   1503     return rv;
   1504 }
   1505 
   1506 /*
   1507  * Function:
   1508  *      phy_54616_ability_advert_set
   1509  * Purpose:
   1510  *      Set the current advertisement for auto-negotiation.
   1511  * Parameters:
   1512  *      unit - StrataSwitch unit #.
   1513  *      port - StrataSwitch port #.
   1514  *      ability - Port ability indicating supported options/speeds.
   1515  * Returns:
   1516  *      SOC_E_XXX
   1517  * Notes:
   1518  *      The advertisement is set only for the ACTIVE medium.
   1519  *      No synchronization performed at this level.
   1520  */
   1521 
   1522 STATIC int
   1523 _phy_54616_fiber_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability)
   1524 {
   1525     phy_ctrl_t  *pc;
   1526     uint16      an_adv;
   1527 
   1528     pc = EXT_PHY_SW_STATE(unit, port);
   1529 
   1530     /* Support only full duplex */
   1531     an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? MII_ANP_C37_FD : 0;
   1532     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
   1533     case SOC_PA_PAUSE_TX:
   1534         an_adv |= MII_ANP_C37_ASYM_PAUSE;
   1535         break;
   1536     case SOC_PA_PAUSE_RX:
   1537         an_adv |= MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE;
   1538         break;
   1539     case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   1540         an_adv |= MII_ANP_C37_PAUSE;
   1541         break;
   1542     }
   1543 
   1544     SOC_IF_ERROR_RETURN
   1545         (WRITE_PHY54616_1000X_MII_ANAr(unit, pc, an_adv));
   1546 
   1547     return SOC_E_NONE;
   1548 }
   1549 
   1550 
   1551 STATIC int
   1552 phy_54616_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability)
   1553 {
   1554     phy_ctrl_t    *pc;
   1555 
   1556     pc = EXT_PHY_SW_STATE(unit, port);
   1557 
   1558     if ( PHY_COPPER_MODE(unit, port) ) {
   1559         SOC_IF_ERROR_RETURN
   1560             (phy_fe_ge_ability_advert_set(unit, port, ability));
   1561         pc->copper.advert_ability = *ability;
   1562     } else { 
   1563         SOC_IF_ERROR_RETURN
   1564             (_phy_54616_fiber_ability_advert_set(unit, port, ability));
   1565         pc->fiber.advert_ability = *ability;
   1566     }
   1567 
   1568     /* EEE settings */
   1569     if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) {
   1570         uint16	eee_ability = 0;
   1571 
   1572         if ( ability->eee & SOC_PA_EEE_1GB_BASET ) {
   1573             eee_ability |= 0x4;
   1574         }
   1575         if ( ability->eee & SOC_PA_EEE_100MB_BASETX ) {
   1576             eee_ability |= 0x2;
   1577         }
   1578         if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) ) {
   1579             SOC_IF_ERROR_RETURN
   1580                     (MODIFY_PHY54618_EEE_ADVr(unit, pc, eee_ability, 0x0006));
   1581         } else {
   1582             SOC_IF_ERROR_RETURN
   1583                     (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0000, 0x0006));
   1584         }
   1585     }
   1586 
   1587     return SOC_E_NONE;
   1588 }
   1589 
   1590 /*
   1591  * Function:
   1592  *      phy_54616_ability_advert_get
   1593  * Purpose:
   1594  *      Get the current advertisement for auto-negotiation.
   1595  * Parameters:
   1596  *      unit - StrataSwitch unit #.
   1597  *      port - StrataSwitch port #.
   1598  *      ability - Port ability indicating supported options/speeds.
   1599  * Returns:
   1600  *      SOC_E_XXX
   1601  * Notes:
   1602  *      The advertisement is retrieved for the ACTIVE medium.
   1603  *      No synchronization performed at this level.
   1604  */
   1605 
   1606 STATIC int
   1607 _phy_54616_fiber_ability_advert_get(int unit, soc_port_t port,soc_port_ability_t *ability)
   1608 {
   1609     phy_ctrl_t  *pc;
   1610     uint16      an_adv;
   1611 
   1612     pc = EXT_PHY_SW_STATE(unit, port);
   1613 
   1614     sal_memset(ability, 0, sizeof(*ability));
   1615 
   1616     SOC_IF_ERROR_RETURN
   1617         (READ_PHY54616_1000X_MII_ANAr(unit, pc, &an_adv));
   1618 
   1619     switch ( an_adv & (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE) ) {
   1620     case MII_ANP_C37_ASYM_PAUSE:
   1621         ability->pause |= SOC_PA_PAUSE_TX;
   1622         break;
   1623     case (MII_ANP_C37_ASYM_PAUSE | MII_ANP_C37_PAUSE):
   1624         ability->pause |= SOC_PA_PAUSE_RX;
   1625         break;
   1626     case MII_ANP_C37_PAUSE:
   1627         ability->pause |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1628         break;
   1629     }
   1630 
   1631     ability->speed_full_duplex |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0;
   1632 
   1633     return SOC_E_NONE;
   1634 }
   1635 
   1636 STATIC int
   1637 phy_54616_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1638 {
   1639     if ( PHY_COPPER_MODE(unit, port) ) {
   1640         SOC_IF_ERROR_RETURN
   1641             (phy_fe_ge_ability_advert_get(unit, port, ability));
   1642 
   1643         /* EEE settings */
   1644         if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) {
   1645             uint16  eee_ability = 0;
   1646             phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port);
   1647 
   1648             SOC_IF_ERROR_RETURN
   1649                 (READ_PHY54618_EEE_ADVr(unit, pc, &eee_ability));
   1650             if ( eee_ability & 0x04 ) {
   1651                 ability->eee |= SOC_PA_EEE_1GB_BASET;
   1652             }
   1653             if ( eee_ability & 0x02 ) {
   1654                 ability->eee |= SOC_PA_EEE_100MB_BASETX;
   1655             }
   1656         }
   1657     } else {    /* PHY_FIBER_MODE */
   1658         SOC_IF_ERROR_RETURN
   1659             (_phy_54616_fiber_ability_advert_get(unit, port, ability));
   1660     }
   1661     return SOC_E_NONE;
   1662 }
   1663 
   1664 /*
   1665  * Function:
   1666  *      phy_54616_ability_remote_get
   1667  * Purpose:
   1668  *      Get partners current advertisement for auto-negotiation.
   1669  * Parameters:
   1670  *      unit - StrataSwitch unit #.
   1671  *      port - StrataSwitch port #.
   1672  *      ability - Port ability indicating supported options/speeds.
   1673  * Returns:
   1674  *      SOC_E_XXX
   1675  * Notes:
   1676  *      The remote advertisement is retrieved for the ACTIVE medium.
   1677  *      No synchronization performed at this level. If Autonegotiation is
   1678  *      disabled or in progress, this routine will return an error.
   1679  */
   1680 
   1681 STATIC int
   1682 _phy_54616_fiber_ability_remote_get(int unit, soc_port_t port,
   1683                                soc_port_ability_t *ability)
   1684 {
   1685     uint16            an_adv, data;
   1686     phy_ctrl_t       *pc;
   1687 
   1688     pc = EXT_PHY_SW_STATE(unit, port);
   1689 
   1690     sal_memset(ability, 0, sizeof(*ability));
   1691 
   1692     SOC_IF_ERROR_RETURN
   1693         (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &data));
   1694     if (!(data & MII_CTRL_AE)) {
   1695         return SOC_E_DISABLED;
   1696     }
   1697     SOC_IF_ERROR_RETURN
   1698         (READ_PHY54616_1000X_MII_STATr(unit, pc, &data));
   1699 
   1700     if (data & MII_STAT_AN_DONE) {
   1701         /* Decode remote advertisement only when link is up and autoneg is
   1702          * completed.
   1703          */
   1704 
   1705         SOC_IF_ERROR_RETURN
   1706             (READ_PHY54616_1000X_MII_ANPr(unit, pc, &an_adv));
   1707 
   1708         ability->speed_full_duplex |= (an_adv & MII_ANP_C37_FD) ? SOC_PA_SPEED_1000MB : 0;
   1709         ability->speed_half_duplex |= (an_adv & MII_ANP_C37_HD) ? SOC_PA_SPEED_1000MB : 0;
   1710 
   1711         switch (an_adv & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
   1712             case MII_ANP_C37_PAUSE:
   1713                 ability->pause |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   1714                 break;
   1715             case MII_ANP_C37_ASYM_PAUSE:
   1716                 ability->pause |= SOC_PA_PAUSE_TX;
   1717                 break;
   1718             case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE:
   1719                 ability->pause |= SOC_PA_PAUSE_RX;
   1720                 break;
   1721         }
   1722 
   1723     } else {
   1724         /* Simply return local abilities */
   1725         SOC_IF_ERROR_RETURN
   1726             (phy_54616_ability_advert_get(unit, port, ability));
   1727     }
   1728 
   1729     return (SOC_E_NONE);
   1730 }
   1731 
   1732 STATIC int
   1733 phy_54616_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1734 {
   1735     if ( PHY_COPPER_MODE(unit, port) ) {
   1736         /* EEE settings */
   1737         if ( PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) {
   1738             phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port);
   1739             uint16       eee_resolution;
   1740 
   1741             SOC_IF_ERROR_RETURN
   1742                 (READ_PHY54618_EEE_RESOLUTION_STATr(unit, pc, &eee_resolution));
   1743             if ( eee_resolution & 0x04 ) {
   1744                 ability->eee |= SOC_PA_EEE_1GB_BASET;
   1745             }
   1746             if ( eee_resolution & 0x02 ) {
   1747                 ability->eee |= SOC_PA_EEE_100MB_BASETX;
   1748             }
   1749         }
   1750 
   1751         SOC_IF_ERROR_RETURN
   1752             (phy_fe_ge_ability_remote_get(unit, port, ability));
   1753     } else {    /* PHY_FIBER_MODE */
   1754         SOC_IF_ERROR_RETURN
   1755             (_phy_54616_fiber_ability_remote_get(unit, port, ability));
   1756     }
   1757     return SOC_E_NONE;
   1758 }
   1759 
   1760 /*
   1761  * Function:
   1762  *      phy_54616_lb_set
   1763  * Purpose:
   1764  *      Set the local PHY loopback mode.
   1765  * Parameters:
   1766  *      unit - StrataSwitch unit #.
   1767  *      port - StrataSwitch port #.
   1768  *      loopback - Boolean: true = enable loopback, false = disable.
   1769  * Returns:
   1770  *      SOC_E_XXX
   1771  * Notes:
   1772  *      The loopback mode is set only for the ACTIVE medium.
   1773  *      No synchronization performed at this level.
   1774  */
   1775 
   1776 STATIC int
   1777 phy_54616_lb_set(int unit, soc_port_t port, int enable)
   1778 {
   1779     phy_ctrl_t    *pc;
   1780 
   1781     pc = EXT_PHY_SW_STATE(unit, port);
   1782 
   1783 #if AUTO_MDIX_WHEN_AN_DIS
   1784     {
   1785         /* Disable Auto-MDIX When autoneg disabled */
   1786         /* Enable Auto-MDIX When autoneg disabled */
   1787         uint16 data = (enable) ? 0x0000 : 0x0200;
   1788         SOC_IF_ERROR_RETURN
   1789             (MODIFY_PHY_54616_MII_MISC_CTRLr(unit, pc, data, 0x0200)); 
   1790     }
   1791 #endif
   1792 
   1793     if (PHY_COPPER_MODE(unit, port)) {
   1794         SOC_IF_ERROR_RETURN
   1795             (phy_fe_ge_lb_set(unit, port, enable));
   1796     } else { 
   1797         SOC_IF_ERROR_RETURN
   1798             (MODIFY_PHY54616_1000X_MII_CTRLr(unit, pc, (enable) ? MII_CTRL_LE : 0, MII_CTRL_LE));
   1799                   
   1800     }
   1801     LOG_INFO(BSL_LS_SOC_PHY,
   1802              (BSL_META_U(unit,
   1803                          "phy_54616_lb_set: u=%d p=%d en=%d\n"), unit, port, enable));
   1804 
   1805     return SOC_E_NONE;
   1806 }
   1807 
   1808 /*
   1809  * Function:
   1810  *      phy_54616_lb_get
   1811  * Purpose:
   1812  *      Get the local PHY loopback mode.
   1813  * Parameters:
   1814  *      unit - StrataSwitch unit #.
   1815  *      port - StrataSwitch port #.
   1816  *      loopback - (OUT) Boolean: true = enable loopback, false = disable.
   1817  * Returns:
   1818  *      SOC_E_XXX
   1819  * Notes:
   1820  *      The loopback mode is retrieved for the ACTIVE medium.
   1821  */
   1822 
   1823 STATIC int
   1824 phy_54616_lb_get(int unit, soc_port_t port, int *enable)
   1825 {
   1826     uint16         data;
   1827     phy_ctrl_t    *pc;
   1828 
   1829     pc = EXT_PHY_SW_STATE(unit, port);
   1830 
   1831     if (PHY_COPPER_MODE(unit, port)) {
   1832         SOC_IF_ERROR_RETURN
   1833             (phy_fe_ge_lb_get(unit, port, enable));
   1834     } else {
   1835        SOC_IF_ERROR_RETURN
   1836            (READ_PHY54616_1000X_MII_CTRLr(unit, pc, &data));
   1837         *enable = (data & MII_CTRL_LE) ? 1 : 0;
   1838     }
   1839 
   1840     return SOC_E_NONE; 
   1841 }
   1842 
   1843 /*
   1844  * Function:
   1845  *      phy_54616_interface_set
   1846  * Purpose:
   1847  *      Set the current operating mode of the PHY.
   1848  * Parameters:
   1849  *      unit - StrataSwitch unit #.
   1850  *      port - StrataSwitch port #.
   1851  *      pif - one of SOC_PORT_IF_*
   1852  * Returns:
   1853  *      SOC_E_NONE - success
   1854  *      SOC_E_UNAVAIL - unsupported interface
   1855  */
   1856 
   1857 STATIC int
   1858 phy_54616_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   1859 {
   1860     COMPILER_REFERENCE(unit);
   1861     COMPILER_REFERENCE(port);
   1862     COMPILER_REFERENCE(pif);
   1863 
   1864     return SOC_E_NONE;
   1865 }
   1866 
   1867 /*
   1868  * Function:
   1869  *      phy_54616_interface_get
   1870  * Purpose:
   1871  *      Get the current operating mode of the PHY.
   1872  * Parameters:
   1873  *      unit - StrataSwitch unit #.
   1874  *      port - StrataSwitch port #.
   1875  *      pif - (OUT) one of SOC_PORT_IF_*
   1876  * Returns:
   1877  *      SOC_E_NONE
   1878  */
   1879 
   1880 STATIC int
   1881 phy_54616_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   1882 {
   1883     phy_ctrl_t    *pc;
   1884 
   1885     pc = EXT_PHY_SW_STATE(unit, port);
   1886 
   1887     *pif = pc->interface;
   1888     return SOC_E_NONE;
   1889 }
   1890 
   1891 /*
   1892  * Function:
   1893  *      phy_54616_ability_local_get
   1894  * Purpose:
   1895  *      Get the abilities of the local gigabit PHY.
   1896  * Parameters:
   1897  *      unit - StrataSwitch unit #.
   1898  *      port - StrataSwitch port #.
   1899  *      ability - return device's abilities.
   1900  * Returns:
   1901  *      SOC_E_NONE
   1902  * Notes:
   1903  *      The ability is retrieved only for the ACTIVE medium.
   1904  */
   1905 
   1906 STATIC int
   1907 _phy_54616_copper_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1908 {
   1909     ability->speed_half_duplex  = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB;
   1910     ability->speed_full_duplex  = SOC_PA_SPEED_1000MB | SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB;
   1911 
   1912     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   1913     ability->interface = SOC_PA_INTF_SGMII | SOC_PA_INTF_RGMII;
   1914     ability->medium    = SOC_PA_MEDIUM_COPPER;
   1915     ability->loopback  = SOC_PA_LB_PHY;
   1916     ability->flags     = SOC_PA_AUTONEG;
   1917 
   1918     return (SOC_E_NONE);
   1919 }
   1920 
   1921 STATIC int
   1922 _phy_54616_fiber_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1923 {
   1924 
   1925     ability->speed_half_duplex  = SOC_PA_SPEED_1000MB;
   1926     ability->speed_full_duplex  = SOC_PA_SPEED_1000MB;
   1927 
   1928     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   1929     ability->interface = SOC_PA_INTF_RGMII;
   1930     ability->medium    = SOC_PA_MEDIUM_FIBER;
   1931     ability->loopback  = SOC_PA_LB_PHY;
   1932     ability->flags     = SOC_PA_ABILITY_NONE;
   1933 
   1934     return (SOC_E_NONE);
   1935 }
   1936 
   1937 STATIC int
   1938 phy_54616_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   1939 {
   1940     if (NULL == ability) {
   1941         return SOC_E_PARAM;
   1942     }
   1943 
   1944     if (PHY_COPPER_MODE(unit, port)) {
   1945         SOC_IF_ERROR_RETURN(_phy_54616_copper_ability_local_get(unit, port, ability));
   1946     } else {
   1947         SOC_IF_ERROR_RETURN(_phy_54616_fiber_ability_local_get(unit, port, ability));
   1948     }
   1949 
   1950     return (SOC_E_NONE);
   1951 }
   1952 
   1953 
   1954 /*
   1955  * Function:
   1956  *      phy_54616_mdix_set
   1957  * Description:
   1958  *      Set the Auto-MDIX mode of a port/PHY
   1959  * Parameters:
   1960  *      unit - Device number
   1961  *      port - Port number
   1962  *      mode - One of:
   1963  *              SOC_PORT_MDIX_AUTO
   1964  *                      Enable auto-MDIX when autonegotiation is enabled
   1965  *              SOC_PORT_MDIX_FORCE_AUTO
   1966  *                      Enable auto-MDIX always
   1967  *              SOC_PORT_MDIX_NORMAL
   1968  *                      Disable auto-MDIX
   1969  *              SOC_PORT_MDIX_XOVER
   1970  *                      Disable auto-MDIX, and swap cable pairs
   1971  * Return Value:
   1972  *      SOC_E_XXX
   1973  */
   1974 STATIC int
   1975 phy_54616_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode)
   1976 {
   1977     phy_ctrl_t    *pc;
   1978     int                  speed;
   1979 
   1980     pc = EXT_PHY_SW_STATE(unit, port);
   1981     if (PHY_COPPER_MODE(unit, port)) {
   1982         switch (mode) {
   1983         case SOC_PORT_MDIX_AUTO:
   1984             /* Clear bit 14 for automatic MDI crossover */
   1985             SOC_IF_ERROR_RETURN
   1986                 (MODIFY_PHY54616_MII_ECRr(unit, pc, 0, 0x4000));
   1987 
   1988             /* Clear bit 9 to disable forced auto MDI xover */
   1989             SOC_IF_ERROR_RETURN
   1990                 (MODIFY_PHY54616_MII_MISC_CTRLr(unit, pc, 0, 0x0200));
   1991             break;
   1992 
   1993         case SOC_PORT_MDIX_FORCE_AUTO:
   1994             /* Clear bit 14 for automatic MDI crossover */
   1995             SOC_IF_ERROR_RETURN
   1996                 (MODIFY_PHY54616_MII_ECRr(unit, pc, 0, 0x4000));
   1997 
   1998             /* Set bit 9 to disable forced auto MDI xover */
   1999             SOC_IF_ERROR_RETURN
   2000                 (MODIFY_PHY54616_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200));
   2001             break;
   2002 
   2003         case SOC_PORT_MDIX_NORMAL:
   2004             SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed));
   2005             if (speed == 0 || speed == 10 || speed == 100) {
   2006                 /* Set bit 14 for automatic MDI crossover */
   2007                 SOC_IF_ERROR_RETURN
   2008                     (MODIFY_PHY54616_MII_ECRr(unit, pc, 0x4000, 0x4000));
   2009 
   2010                 SOC_IF_ERROR_RETURN
   2011                     (WRITE_PHY54616_TEST1r(unit, pc, 0));
   2012             } else {
   2013                 return SOC_E_UNAVAIL;
   2014             }
   2015             break;
   2016 
   2017         case SOC_PORT_MDIX_XOVER:
   2018             SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed));
   2019             if (speed == 0 || speed == 10 || speed == 100) {
   2020                 /* Set bit 14 for automatic MDI crossover */
   2021                 SOC_IF_ERROR_RETURN
   2022                     (MODIFY_PHY54616_MII_ECRr(unit, pc, 0x4000, 0x4000));
   2023 
   2024                 SOC_IF_ERROR_RETURN
   2025                     (WRITE_PHY54616_TEST1r(unit, pc, 0x0080));
   2026             } else {
   2027                 return SOC_E_UNAVAIL;
   2028             }
   2029             break;
   2030 
   2031         default:
   2032             return SOC_E_PARAM;
   2033         }
   2034         pc->copper.mdix = mode;
   2035     } else {    /* fiber */
   2036         if (mode != SOC_PORT_MDIX_NORMAL) {
   2037             return SOC_E_UNAVAIL;
   2038         }
   2039     }
   2040     return SOC_E_NONE;
   2041 }        
   2042 
   2043 #if defined(BCM_WARM_BOOT_SUPPORT)
   2044 /*
   2045  * Function:
   2046  *      phy_54616_mdix_wb_update
   2047  * Description:
   2048  *      Read the hw, derive the mode and update the mdix mode in sw structure
   2049  *      during wb.
   2050  * Parameters:
   2051  *      unit - (IN) Device number
   2052  *      port - (IN) Port number
   2053  *      mode - (OUT) :One of:
   2054  *              SOC_PORT_MDIX_AUTO
   2055  *                      Enable auto-MDIX when autonegotiation is enabled
   2056  *              SOC_PORT_MDIX_FORCE_AUTO
   2057  *                      Enable auto-MDIX always
   2058  *              SOC_PORT_MDIX_NORMAL
   2059  *                      Disable auto-MDIX
   2060  *              SOC_PORT_MDIX_XOVER
   2061  *                      Disable auto-MDIX, and swap cable pairs
   2062  * Return Value:
   2063  *      SOC_E_XXX
   2064  */
   2065 STATIC int
   2066 phy_54616_mdix_wb_update(int unit, soc_port_t port)
   2067 {
   2068     phy_ctrl_t    *pc;
   2069     int            speed;
   2070     int            mode = 0;
   2071     uint16         val = 0;
   2072 
   2073     pc = EXT_PHY_SW_STATE(unit, port);
   2074 
   2075     if (PHY_COPPER_MODE(unit, port)) {
   2076         /* Check bit 14 for automatic MDI crossover */
   2077         SOC_IF_ERROR_RETURN (READ_PHY54616_MII_ECRr(unit, pc, &val));
   2078         if(val & 0x4000) {
   2079             SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed));
   2080             if (speed == 0 || speed == 10 || speed == 100) {
   2081                 SOC_IF_ERROR_RETURN (READ_PHY54616_TEST1r(unit, pc, &val));
   2082                 if (0 == val) {
   2083                     mode = SOC_PORT_MDIX_NORMAL;
   2084                 } else if (0x80 == val) {
   2085                     mode = SOC_PORT_MDIX_XOVER;
   2086                 } else {
   2087                     return SOC_E_UNAVAIL;
   2088                 }
   2089             } else {
   2090                 return SOC_E_UNAVAIL;
   2091             }
   2092         } else {
   2093             /* Check bit 9 forced auto MDI xover */
   2094             SOC_IF_ERROR_RETURN (READ_PHY54616_MII_MISC_CTRLr(unit, pc,&val));
   2095             if (val & 0x200) {
   2096                 /* bit 9 Set, forced auto MDI xover */
   2097                 mode = SOC_PORT_MDIX_FORCE_AUTO;
   2098             } else {
   2099                 /* bit 9 Clear, forced auto MDI xover */
   2100                 mode = SOC_PORT_MDIX_AUTO;
   2101             }
   2102         }
   2103         pc->copper.mdix = mode;
   2104     } else {
   2105         /* fiber */
   2106         mode = SOC_PORT_MDIX_NORMAL;
   2107     }
   2108     return SOC_E_NONE;
   2109 }
   2110 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */
   2111 
   2112 
   2113 /*
   2114  * Function:
   2115  *      phy_54616_mdix_get
   2116  * Description:
   2117  *      Get the Auto-MDIX mode of a port/PHY
   2118  * Parameters:
   2119  *      unit - Device number
   2120  *      port - Port number
   2121  *      mode - (Out) One of:
   2122  *              SOC_PORT_MDIX_AUTO
   2123  *                      Enable auto-MDIX when autonegotiation is enabled
   2124  *              SOC_PORT_MDIX_FORCE_AUTO
   2125  *                      Enable auto-MDIX always
   2126  *              SOC_PORT_MDIX_NORMAL
   2127  *                      Disable auto-MDIX
   2128  *              SOC_PORT_MDIX_XOVER
   2129  *                      Disable auto-MDIX, and swap cable pairs
   2130  * Return Value:
   2131  *      SOC_E_XXX
   2132  */
   2133 STATIC int
   2134 phy_54616_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode)
   2135 {
   2136     phy_ctrl_t    *pc;
   2137     int            speed;
   2138 
   2139     if (mode == NULL) {
   2140         return SOC_E_PARAM;
   2141     }
   2142 
   2143 #if defined(BCM_WARM_BOOT_SUPPORT)
   2144     if (SOC_WARM_BOOT(unit)) {
   2145         return phy_54616_mdix_wb_update(unit, port);
   2146     }
   2147 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */
   2148 
   2149     pc = EXT_PHY_SW_STATE(unit, port);
   2150 
   2151     if (PHY_COPPER_MODE(unit, port)) {
   2152         SOC_IF_ERROR_RETURN(phy_54616_speed_get(unit, port, &speed));
   2153         if (speed == 1000) {
   2154            *mode = SOC_PORT_MDIX_AUTO;
   2155         } else {
   2156             *mode = pc->copper.mdix;
   2157         }
   2158     } else {
   2159         *mode = SOC_PORT_MDIX_NORMAL;
   2160     }
   2161 
   2162     return SOC_E_NONE;
   2163 }    
   2164 
   2165 /*
   2166  * Function:
   2167  *      phy_54616_mdix_status_get
   2168  * Description:
   2169  *      Get the current MDIX status on a port/PHY
   2170  * Parameters:
   2171  *      unit    - Device number
   2172  *      port    - Port number
   2173  *      status  - (OUT) One of:
   2174  *              SOC_PORT_MDIX_STATUS_NORMAL
   2175  *                      Straight connection
   2176  *              SOC_PORT_MDIX_STATUS_XOVER
   2177  *                      Crossover has been performed
   2178  * Return Value:
   2179  *      SOC_E_XXX
   2180  */
   2181 STATIC int
   2182 phy_54616_mdix_status_get(int unit, soc_port_t port, 
   2183                          soc_port_mdix_status_t *status)
   2184 {
   2185     phy_ctrl_t    *pc;
   2186     uint16          data;
   2187 
   2188     if (status == NULL) {
   2189         return SOC_E_PARAM;
   2190     }
   2191 
   2192     pc = EXT_PHY_SW_STATE(unit, port);
   2193 
   2194     if (PHY_COPPER_MODE(unit, port)) {
   2195         SOC_IF_ERROR_RETURN
   2196             (READ_PHY54616_MII_ESRr(unit, pc, &data));
   2197         if (data & 0x2000) {
   2198             *status = SOC_PORT_MDIX_STATUS_XOVER;
   2199         } else {
   2200             *status = SOC_PORT_MDIX_STATUS_NORMAL;
   2201         }
   2202     } else {
   2203         *status = SOC_PORT_MDIX_STATUS_NORMAL;
   2204     }
   2205 
   2206     return SOC_E_NONE;
   2207 }    
   2208 
   2209 STATIC int
   2210 _phy_54616_power_mode_set (int unit, soc_port_t port, int mode)
   2211 {
   2212     phy_ctrl_t  *pc = EXT_PHY_SW_STATE(unit, port);
   2213 
   2214     if (pc->power_mode == mode) {
   2215         return SOC_E_NONE;
   2216     }
   2217 
   2218     /* Auto Power-Down   Reg.0x1C, shadow 0x0A, bit[5] Auto Power Down  Mode */
   2219     /* Autodetect Medium Reg.0x1C, shadow 0x1E, bit[5] Auto Fiber Power Mode */
   2220     if ( (mode == SOC_PHY_CONTROL_POWER_FULL) ||
   2221          (mode == SOC_PHY_CONTROL_POWER_AUTO_DISABLE) ) {
   2222         /* disable the auto power mode */
   2223         SOC_IF_ERROR_RETURN(
   2224             MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc,
   2225                                     0 , PHY_54616_AUTO_PWRDWN_EN) );
   2226         SOC_IF_ERROR_RETURN(
   2227             MODIFY_PHY54616_AUTO_DETECT_MEDIUMr(unit,pc,
   2228                                     0 , PHY_54616_FiBER_AUTO_PWRDWN_EN) );
   2229     } else if ( (mode == SOC_PHY_CONTROL_POWER_AUTO) ||
   2230                 (mode == SOC_PHY_CONTROL_POWER_AUTO_FULL) ) {
   2231         /* enable the auto power mode */
   2232         SOC_IF_ERROR_RETURN(
   2233             MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc,
   2234                                     PHY_54616_AUTO_PWRDWN_EN,
   2235                                     PHY_54616_AUTO_PWRDWN_EN) );
   2236         SOC_IF_ERROR_RETURN(
   2237             MODIFY_PHY54616_AUTO_DETECT_MEDIUMr(unit,pc,
   2238                                     PHY_54616_FiBER_AUTO_PWRDWN_EN,
   2239                                     PHY_54616_FiBER_AUTO_PWRDWN_EN) );
   2240     } /* support only FULL & AUTO, discard POWER_LOW & POWER_AUTO_LOW modes */
   2241 
   2242     pc->power_mode = mode;
   2243     return SOC_E_NONE;
   2244 }
   2245 
   2246 /*
   2247  * Function:
   2248  *      _phy_54618_eee_enable
   2249  * Purpose:
   2250  *      Enable or disable EEE (Native)
   2251  * Parameters:
   2252  *      unit   - StrataSwitch unit #.
   2253  *      port   - StrataSwitch port #.
   2254  *      enable - Enable Native EEE
   2255  * Returns:
   2256  *      SOC_E_NONE
   2257  */
   2258 STATIC int
   2259 _phy_54618_eee_enable(int unit, soc_port_t port, int enable)
   2260 {
   2261     phy_ctrl_t *pc;
   2262     
   2263     if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2264         return SOC_E_UNAVAIL;
   2265     }
   2266     pc = EXT_PHY_SW_STATE(unit, port);
   2267 
   2268     if ( enable == 1 ) {
   2269         SOC_IF_ERROR_RETURN
   2270             (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x8000, 0x8000)); /* 7.803d enable EEE */
   2271         SOC_IF_ERROR_RETURN
   2272             (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0006, 0x0006));
   2273         pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   2274 
   2275         SOC_IF_ERROR_RETURN            /* native mode, disable AutogrEEEn */
   2276             (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0000, 0x0001));
   2277         SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */
   2278     } else {  /* enable==0 */
   2279         SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x1)); /* exp af */
   2280         pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   2281         SOC_IF_ERROR_RETURN
   2282             (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0000, 0x0006));
   2283         SOC_IF_ERROR_RETURN
   2284             (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x0000, 0x8000)); /* 7.803d disable EEE */
   2285     }
   2286 
   2287     return SOC_E_NONE;
   2288 }
   2289 
   2290 /*
   2291  * Function:
   2292  *      _phy_54618_eee_auto_enable
   2293  * Purpose:
   2294  *      Enable or disable EEE (Native)
   2295  * Parameters:
   2296  *      unit   - StrataSwitch unit #.
   2297  *      port   - StrataSwitch port #.
   2298  *      enable - Enable Native EEE
   2299  * Returns:
   2300  *      SOC_E_NONE
   2301  */
   2302 STATIC int
   2303 _phy_54618_eee_auto_enable(int unit, soc_port_t port, int enable)
   2304 {
   2305     phy_ctrl_t *pc;
   2306     
   2307     if ( ! PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) {
   2308         return SOC_E_UNAVAIL;
   2309     }
   2310     pc = EXT_PHY_SW_STATE(unit, port);
   2311 
   2312     if ( enable == 1 ) {
   2313         SOC_IF_ERROR_RETURN
   2314             (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x8000, 0x8000)); /* 7.803d enable EEE */
   2315         SOC_IF_ERROR_RETURN
   2316             (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0006, 0x0006));
   2317         pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   2318 
   2319         SOC_IF_ERROR_RETURN            /* enable AutogrEEEn */
   2320             (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0001, 0x0001));
   2321         SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */
   2322     } else {  /*enable == 0 */
   2323         SOC_IF_ERROR_RETURN(PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x3)); /* exp af */
   2324         pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   2325         SOC_IF_ERROR_RETURN
   2326             (MODIFY_PHY54618_EEE_ADVr(unit, pc, 0x0000, 0x0006));
   2327         SOC_IF_ERROR_RETURN
   2328             (MODIFY_PHY54618_EEE_CTRLr(unit, pc, 0x0000, 0x8000)); /* 7.803d disable EEE */
   2329     }
   2330 
   2331     return SOC_E_NONE;
   2332 }
   2333 
   2334 
   2335 /*
   2336  * Function:
   2337  *      phy_54616_control_set
   2338  * Purpose:
   2339  *      Configure PHY device specific control fucntion.
   2340  * Parameters:
   2341  *      unit  - StrataSwitch unit #.
   2342  *      port  - StrataSwitch port #.
   2343  *      type  - Control to update
   2344  *      value - New setting for the control
   2345  * Returns:
   2346  *      SOC_E_NONE
   2347  */
   2348 STATIC int
   2349 phy_54616_control_set(int unit, soc_port_t port,
   2350                      soc_phy_control_t type, uint32 value)
   2351 {
   2352     int rv;
   2353     phy_ctrl_t *pc;
   2354     uint16 data16;
   2355     int saved_autoneg;
   2356 
   2357     PHY_CONTROL_TYPE_CHECK(type);
   2358 
   2359     pc = EXT_PHY_SW_STATE(unit, port);
   2360     rv = SOC_E_NONE;
   2361 
   2362     switch(type) {
   2363     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   2364         if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   2365             /* RXC SyncE on/off. Expansion Register 0Eh, bit[4] */
   2366             SOC_IF_ERROR_RETURN
   2367                 (MODIFY_PHY54616_EXP_SYNCE_CTRLr(unit, pc,
   2368                                                  value ? (1U << 4) : 0, 1U << 4));
   2369         }
   2370         else if ( pc->phy_rev == 0xB ) {    /* BCM54616 Rev.B only */
   2371             SOC_IF_ERROR_RETURN
   2372                 (WRITE_PHY54616_EXP_SGMII_REC_CTRLr(unit, pc,
   2373                                                     value ? (1U << 4) : 0));
   2374         }
   2375         break;
   2376 
   2377     case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE:
   2378         if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   2379             /* CLK125 SyncE on/off. Top-Level Expansion Reg. 34h, bit[3] */
   2380             SOC_IF_ERROR_RETURN
   2381                 (MODIFY_PHY54616_TOPLVL_CLK125_ADCr(unit, pc,
   2382                                                     value ? (1U << 3) : 0, 1U << 3));
   2383         }
   2384         break;
   2385 
   2386     case SOC_PHY_CONTROL_POWER:
   2387         rv = _phy_54616_power_mode_set(unit,port,value);
   2388         break;
   2389 
   2390     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   2391         if (value <= PHY_54616_AUTO_PWRDWN_WAKEUP_MAX) {
   2392 
   2393             /* at least one unit */
   2394             if (value < PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT) {
   2395                 value = PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT;
   2396             }
   2397         } else { /* anything more then max, set to the max */
   2398             value = PHY_54616_AUTO_PWRDWN_WAKEUP_MAX;
   2399         }
   2400         SOC_IF_ERROR_RETURN
   2401             (MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc,
   2402                       value/PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT,
   2403                       PHY_54616_AUTO_PWRDWN_WAKEUP_MASK));
   2404         break;
   2405 
   2406     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   2407         /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */
   2408         if (value < PHY_54616_AUTO_PWRDWN_SLEEP_MAX) {
   2409             data16 = 0; /* anything less than 5.4s, default to 2.7s */
   2410         } else {
   2411             data16 = PHY_54616_AUTO_PWRDWN_SLEEP_MASK;
   2412         }
   2413         SOC_IF_ERROR_RETURN
   2414             (MODIFY_PHY54616_AUTO_POWER_DOWNr(unit,pc,
   2415                       data16,
   2416                       PHY_54616_AUTO_PWRDWN_SLEEP_MASK));
   2417         break;
   2418 
   2419     case SOC_PHY_CONTROL_EEE:
   2420         if ( ! PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) {
   2421             rv = SOC_E_UNAVAIL;
   2422         }
   2423 
   2424         if (value == 1) {
   2425             /* Enable Native EEE */
   2426             SOC_IF_ERROR_RETURN
   2427                 (_phy_54618_eee_enable(unit, port, 1));
   2428             saved_autoneg = pc->copper.autoneg_enable;
   2429             /* Initiate AN */
   2430             SOC_IF_ERROR_RETURN
   2431                 (phy_54616_autoneg_set(unit, port, 1)); /* must AN=on for EEE */
   2432             pc->copper.autoneg_enable = saved_autoneg;
   2433             PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   2434             PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE);    /* nativeEEE */
   2435         } else {
   2436             SOC_IF_ERROR_RETURN
   2437                 (_phy_54618_eee_enable(unit, port, 0));
   2438             /* Initiate AN if administratively enabled */
   2439             SOC_IF_ERROR_RETURN
   2440                 (phy_54616_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0));
   2441             PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   2442         }
   2443         break;
   2444 
   2445     case SOC_PHY_CONTROL_EEE_AUTO:
   2446         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2447             rv = SOC_E_UNAVAIL;
   2448         }
   2449 
   2450         if (value == 1) {
   2451             /* Disable Native EEE */
   2452             SOC_IF_ERROR_RETURN
   2453                 (_phy_54618_eee_enable(unit, port, 0));
   2454             /* Enable Auto EEE */
   2455             SOC_IF_ERROR_RETURN
   2456                 (_phy_54618_eee_auto_enable(unit, port, 1));
   2457             saved_autoneg = pc->copper.autoneg_enable;
   2458             /* Initiate AN */
   2459             SOC_IF_ERROR_RETURN
   2460                 (phy_54616_autoneg_set(unit, port, 1));
   2461             pc->copper.autoneg_enable = saved_autoneg;
   2462             PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   2463             PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_MODE);    /* autoEEE */
   2464         } else {
   2465             /* Disable Auto EEE */
   2466             SOC_IF_ERROR_RETURN
   2467                 (_phy_54618_eee_auto_enable(unit, port, 0));
   2468             /* Initiate AN if administratively enabled */
   2469             SOC_IF_ERROR_RETURN
   2470                 (phy_54616_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0));
   2471             PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   2472         }
   2473         break;
   2474 
   2475     case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD:
   2476         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2477             rv = SOC_E_UNAVAIL;
   2478         }
   2479 
   2480         if (value > 7) { /* Values needs to between 0 to 7 (inclusive) */
   2481             rv = SOC_E_CONFIG;
   2482         }
   2483 
   2484         SOC_IF_ERROR_RETURN
   2485             (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, value<<8, 0x0700));
   2486         /* Setting GPHY core, MII buffer register as well */
   2487         SOC_IF_ERROR_RETURN
   2488            (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 
   2489                                                               value<<8, 0x0700));
   2490         break;
   2491 
   2492     case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY:
   2493         if ( ! PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE) ) {
   2494             rv = SOC_E_UNAVAIL;
   2495         }
   2496         /* Fixed latency can have only 0 or 1 value  */
   2497         if ((value != FALSE) && (value != TRUE)) {
   2498             return SOC_E_PARAM;
   2499         }
   2500         if ( value == FALSE ) {  
   2501             /* Sets Variable Latency */
   2502             SOC_IF_ERROR_RETURN
   2503                 (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0004, 0x0004));
   2504             /* Setting GPHY core, MII buffer register as well */
   2505             SOC_IF_ERROR_RETURN
   2506                (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc,
   2507                                                                   0x0004, 0x0004));
   2508         } else {
   2509             /* Sets Fixed Latency */
   2510             SOC_IF_ERROR_RETURN
   2511 	        (MODIFY_PHY54618_EEE_AUTOEEECTRLr(unit, pc, 0x0000, 0x0004));
   2512             /* Setting GPHY core, MII buffer register as well */
   2513             SOC_IF_ERROR_RETURN
   2514                (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc,
   2515                                                                   0x0000, 0x0004));
   2516         } 
   2517         break;
   2518 
   2519     case SOC_PHY_CONTROL_EEE_AUTO_BUFFER_LIMIT:
   2520         /* Buffer limit modification is not allowed */
   2521     case SOC_PHY_CONTROL_EEE_TRANSMIT_WAKE_TIME:
   2522     case SOC_PHY_CONTROL_EEE_RECEIVE_WAKE_TIME:
   2523     case SOC_PHY_CONTROL_EEE_TRANSMIT_SLEEP_TIME:
   2524     case SOC_PHY_CONTROL_EEE_RECEIVE_SLEEP_TIME:
   2525     case SOC_PHY_CONTROL_EEE_TRANSMIT_QUIET_TIME:
   2526     case SOC_PHY_CONTROL_EEE_RECEIVE_QUIET_TIME:
   2527     case SOC_PHY_CONTROL_EEE_TRANSMIT_REFRESH_TIME:
   2528         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2529             rv = SOC_E_UNAVAIL;
   2530         }
   2531 
   2532         /* Time modification not allowed, IEEE EEE spec constants */
   2533         rv = SOC_E_UNAVAIL;
   2534         break;
   2535 
   2536     case SOC_PHY_CONTROL_EEE_STATISTICS_CLEAR:
   2537         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2538             rv = SOC_E_UNAVAIL;
   2539         }
   2540         
   2541         if (value == 1) {
   2542             /* Clearing the stats: Enable clear on Read  */
   2543             SOC_IF_ERROR_RETURN
   2544                (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 
   2545                                                         0x1000, 0x1000));
   2546             /* Read all the stats to clear */
   2547             SOC_IF_ERROR_RETURN
   2548                 (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data16));
   2549             SOC_IF_ERROR_RETURN
   2550                 (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data16));
   2551             SOC_IF_ERROR_RETURN
   2552                 (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data16));
   2553             SOC_IF_ERROR_RETURN
   2554                 (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data16));
   2555             SOC_IF_ERROR_RETURN
   2556                 (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data16));
   2557             SOC_IF_ERROR_RETURN
   2558                 (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data16));
   2559             SOC_IF_ERROR_RETURN
   2560                 (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data16));
   2561             SOC_IF_ERROR_RETURN
   2562                 (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data16));
   2563 
   2564             /* Disable Clear on Read  */
   2565             SOC_IF_ERROR_RETURN
   2566                (MODIFY_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 
   2567                                                         0x0000, 0x1000));
   2568         }
   2569 
   2570         break;
   2571 
   2572     default:
   2573         rv = SOC_E_UNAVAIL;
   2574         break;
   2575     }
   2576     return rv;
   2577 }
   2578 
   2579 /*
   2580  * Function:
   2581  *      phy_54616_control_get
   2582  * Purpose:
   2583  *      Get current control settign of the PHY.
   2584  * Parameters:
   2585  *      unit  - StrataSwitch unit #.
   2586  *      port  - StrataSwitch port #.
   2587  *      type  - Control to update
   2588  *      value - (OUT)Current setting for the control
   2589  * Returns:
   2590  *      SOC_E_NONE
   2591  */
   2592 STATIC int
   2593 phy_54616_control_get(int unit, soc_port_t port,
   2594                      soc_phy_control_t type, uint32 *value)
   2595 {
   2596     int rv;
   2597     phy_ctrl_t *pc;
   2598     uint16 data;
   2599     uint32 temp;
   2600 
   2601     PHY_CONTROL_TYPE_CHECK(type);
   2602 
   2603     pc = EXT_PHY_SW_STATE(unit, port);
   2604     rv = SOC_E_NONE;
   2605 
   2606     switch(type) {
   2607     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   2608         if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   2609             /* RXC SyncE on/off. Expansion Register 0Eh, bit[4] */
   2610             SOC_IF_ERROR_RETURN
   2611                 (READ_PHY54616_EXP_SYNCE_CTRLr(unit, pc, &data));
   2612             *value = (data & (1U << 4)) ? TRUE : FALSE;
   2613         }
   2614         else if ( pc->phy_rev == 0xB ) {    /* BCM54616 Rev.B only */
   2615             SOC_IF_ERROR_RETURN
   2616                 (READ_PHY54616_EXP_SGMII_REC_CTRLr(unit, pc, &data));
   2617             *value = (data & (1U << 4)) ? TRUE : FALSE;
   2618         }
   2619         break;
   2620 
   2621     case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE:
   2622         if ( PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   2623             /* CLK125 SyncE on/off. Top-Level Expansion Reg. 34h, bit[3] */
   2624             SOC_IF_ERROR_RETURN
   2625                 (READ_PHY54616_TOPLVL_CLK125_ADCr(unit, pc, &data));
   2626             *value = (*value || (data & (1U << 3))) ? TRUE : FALSE;
   2627         }
   2628         break;
   2629 
   2630     case SOC_PHY_CONTROL_POWER:
   2631         *value = pc->power_mode;
   2632         break;
   2633 
   2634     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   2635         SOC_IF_ERROR_RETURN
   2636             (READ_PHY54616_AUTO_POWER_DOWNr(unit,pc, &data));
   2637 
   2638         if (data & PHY_54616_AUTO_PWRDWN_SLEEP_MASK) {
   2639             *value = PHY_54616_AUTO_PWRDWN_SLEEP_MAX;
   2640         } else {
   2641             *value = 2700;
   2642         }
   2643         break;
   2644 
   2645     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   2646         SOC_IF_ERROR_RETURN
   2647             (READ_PHY54616_AUTO_POWER_DOWNr(unit,pc, &data));
   2648 
   2649         data &= PHY_54616_AUTO_PWRDWN_WAKEUP_MASK;
   2650         *value = data * PHY_54616_AUTO_PWRDWN_WAKEUP_UNIT;
   2651         break;
   2652 
   2653     case SOC_PHY_CONTROL_EEE:
   2654         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2655             rv = SOC_E_UNAVAIL;
   2656         }
   2657         *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) &&
   2658                  !PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0;
   2659         break;
   2660 
   2661     case SOC_PHY_CONTROL_EEE_AUTO:
   2662         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2663             rv = SOC_E_UNAVAIL;
   2664         }
   2665         *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) &&
   2666                   PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0;
   2667         break;
   2668 
   2669     case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY:
   2670         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2671             rv = SOC_E_UNAVAIL;
   2672         }
   2673         SOC_IF_ERROR_RETURN
   2674             (READ_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data));
   2675         *value = ((data & 0x0004) != 0);
   2676         break;
   2677 
   2678     case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD:
   2679         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2680             rv = SOC_E_UNAVAIL;
   2681         }
   2682         SOC_IF_ERROR_RETURN
   2683             (READ_PHY54618_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data));
   2684         *value = ((data & 0x0700) >> 8);
   2685         break;
   2686 
   2687     case SOC_PHY_CONTROL_EEE_TRANSMIT_EVENTS:
   2688         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2689             rv = SOC_E_UNAVAIL;
   2690         }
   2691         SOC_IF_ERROR_RETURN
   2692             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   2693         SOC_IF_ERROR_RETURN
   2694             (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data));
   2695         temp = data;
   2696         SOC_IF_ERROR_RETURN
   2697             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   2698         SOC_IF_ERROR_RETURN
   2699             (READ_PHY54618_EXP_EEE_TX_EVENTSr(unit, pc, &data));
   2700         temp |= (data << 16);
   2701         *value = temp;
   2702 
   2703         break;
   2704 
   2705     case SOC_PHY_CONTROL_EEE_TRANSMIT_DURATION:
   2706         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2707             rv = SOC_E_UNAVAIL;
   2708         }
   2709         SOC_IF_ERROR_RETURN
   2710             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   2711         SOC_IF_ERROR_RETURN
   2712             (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data));
   2713         temp = data;
   2714         SOC_IF_ERROR_RETURN
   2715             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   2716         SOC_IF_ERROR_RETURN
   2717             (READ_PHY54618_EXP_EEE_TX_DURATIONr(unit, pc, &data));
   2718         temp |= (data << 16);
   2719         *value = temp;
   2720 
   2721         break;
   2722 
   2723     case SOC_PHY_CONTROL_EEE_RECEIVE_EVENTS:
   2724         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2725             rv = SOC_E_UNAVAIL;
   2726         }
   2727         SOC_IF_ERROR_RETURN
   2728             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   2729         SOC_IF_ERROR_RETURN
   2730             (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data));
   2731         temp = data;
   2732         SOC_IF_ERROR_RETURN
   2733             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   2734         SOC_IF_ERROR_RETURN
   2735             (READ_PHY54618_EXP_EEE_RX_EVENTSr(unit, pc, &data));
   2736         temp |= (data << 16);
   2737         *value = temp;
   2738 
   2739         break;
   2740 
   2741     case SOC_PHY_CONTROL_EEE_RECEIVE_DURATION:
   2742         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2743             rv = SOC_E_UNAVAIL;
   2744         }
   2745         SOC_IF_ERROR_RETURN
   2746             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   2747         SOC_IF_ERROR_RETURN
   2748             (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data));
   2749         temp = data;
   2750         SOC_IF_ERROR_RETURN
   2751             (PHY54616_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   2752         SOC_IF_ERROR_RETURN
   2753             (READ_PHY54618_EXP_EEE_RX_DURATIONr(unit, pc, &data));
   2754         temp |= (data << 16);
   2755         *value = temp;
   2756         break;
   2757 
   2758 
   2759     default:
   2760         rv = SOC_E_UNAVAIL;
   2761         break;
   2762     }
   2763     return rv;
   2764 }
   2765 
   2766 /*
   2767  * Function:
   2768  *      phy_54616_cable_diag
   2769  * Purpose:
   2770  *      Run 546x cable diagnostics
   2771  * Parameters:
   2772  *      unit - device number
   2773  *      port - port number
   2774  *      status - (OUT) cable diagnotic status structure
   2775  * Returns:     
   2776  *      SOC_E_XXX
   2777  */
   2778 STATIC int
   2779 phy_54616_cable_diag(int unit, soc_port_t port,
   2780                     soc_port_cable_diag_t *status)
   2781 {
   2782     int                 rv=SOC_E_NONE, rv2, i;
   2783 
   2784     extern int phy_5464_cable_diag_sw(int, soc_port_t , 
   2785                                       soc_port_cable_diag_t *);
   2786 
   2787     if (status == NULL) {
   2788         return SOC_E_PARAM;
   2789     }
   2790 
   2791     status->state = SOC_PORT_CABLE_STATE_OK;
   2792     status->npairs = 4;
   2793     status->fuzz_len = 0;
   2794     for (i = 0; i < 4; i++) {
   2795         status->pair_state[i] = SOC_PORT_CABLE_STATE_OK;
   2796     }
   2797 
   2798     MIIM_LOCK(unit);    /* this locks out linkscan, essentially */
   2799     rv = phy_5464_cable_diag_sw(unit,port, status);
   2800     MIIM_UNLOCK(unit);
   2801     rv2 = 0;
   2802     if (rv <= 0) {      /* don't reset if > 0 -- link was up */
   2803         rv2 = _phy_54616_reset_setup(unit, port);
   2804     }
   2805     if (rv >= 0 && rv2 < 0) {
   2806         return rv2;
   2807     }
   2808     return rv;
   2809 }
   2810 
   2811 /*---------------- BCM54618SE TimeSync support ----------------------------------*/
   2812 
   2813 void _phy_54618e_encode_egress_message_mode(soc_port_phy_timesync_event_message_egress_mode_t mode,
   2814                                             int offset, uint16 *value)
   2815 {
   2816     switch ( mode ) {
   2817     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE:
   2818         *value |= (0x0 << offset);
   2819         break;
   2820     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD:
   2821         *value |= (0x1 << offset);
   2822         break;
   2823     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN:
   2824         *value |= (0x2 << offset);
   2825         break;
   2826     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP:
   2827         *value |= (0x3 << offset);
   2828         break;
   2829     default:
   2830         break;
   2831     }
   2832 }
   2833 
   2834 void _phy_54618e_encode_ingress_message_mode(soc_port_phy_timesync_event_message_ingress_mode_t mode,
   2835                                              int offset, uint16 *value)
   2836 {
   2837     switch ( mode ) {
   2838     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE:
   2839         *value |= (0x0 << offset);
   2840         break;
   2841     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD:
   2842         *value |= (0x1 << offset);
   2843         break;
   2844     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP:
   2845         *value |= (0x2 << offset);
   2846         break;
   2847     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME:
   2848         *value |= (0x3 << offset);
   2849         break;
   2850     default:
   2851         break;
   2852     }
   2853 }
   2854 
   2855 void _phy_54618e_decode_egress_message_mode(uint16 value, int offset,
   2856                                             soc_port_phy_timesync_event_message_egress_mode_t *mode)
   2857 {
   2858     switch ( (value >> offset) & 0x3 ) {
   2859     case 0x0:
   2860         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE;
   2861         break;
   2862     case 0x1:
   2863         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD;
   2864         break;
   2865     case 0x2:
   2866         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN;
   2867         break;
   2868     case 0x3:
   2869         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP;
   2870         break;
   2871     }
   2872 }
   2873 
   2874 void _phy_54618e_decode_ingress_message_mode(uint16 value, int offset,
   2875                                              soc_port_phy_timesync_event_message_ingress_mode_t *mode)
   2876 {
   2877     switch ( (value >> offset) & 0x3 ) {
   2878     case 0x0:
   2879         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE;
   2880         break;
   2881     case 0x1:
   2882         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD;
   2883         break;
   2884     case 0x2:
   2885         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP;
   2886         break;
   2887     case 0x3:
   2888         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME;
   2889         break;
   2890     }
   2891 }
   2892 
   2893 void _phy_54618e_encode_gmode(soc_port_phy_timesync_global_mode_t mode,
   2894                               uint16 *value)
   2895 {
   2896     switch ( mode ) {
   2897     case SOC_PORT_PHY_TIMESYNC_MODE_FREE:
   2898         *value = 0x1;
   2899         break;
   2900     case SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN:
   2901         *value = 0x2;
   2902         break;
   2903     case SOC_PORT_PHY_TIMESYNC_MODE_CPU:
   2904         *value = 0x3;
   2905         break;
   2906     default:
   2907         break;
   2908     }
   2909 }
   2910 
   2911 void _phy_54618e_decode_gmode(uint16 value,
   2912                               soc_port_phy_timesync_global_mode_t *mode)
   2913 {
   2914     switch ( value & 0x3 ) {
   2915     case 0x1:
   2916         *mode = SOC_PORT_PHY_TIMESYNC_MODE_FREE;
   2917         break;
   2918     case 0x2:
   2919         *mode = SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN;
   2920         break;
   2921     case 0x3:
   2922         *mode = SOC_PORT_PHY_TIMESYNC_MODE_CPU;
   2923         break;
   2924     default:
   2925         break;
   2926     }
   2927 }
   2928 
   2929 void _phy_54618e_encode_framesync_mode(soc_port_phy_timesync_framesync_mode_t mode,
   2930                                        uint16 *value)
   2931 {
   2932     switch ( mode ) {
   2933     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0:
   2934         *value = 1U << 0;
   2935         break;
   2936     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1:
   2937         *value = 1U << 1;
   2938         break;
   2939     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT:
   2940         *value = 1U << 2;
   2941         break;
   2942     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU:
   2943         *value = 1U << 3;
   2944         break;
   2945     default:
   2946         break;
   2947     }
   2948 }
   2949 
   2950 void _phy_54618e_decode_framesync_mode(uint16 value,
   2951                                        soc_port_phy_timesync_framesync_mode_t *mode)
   2952 {
   2953     switch ( value & 0xf ) {
   2954     case 1U << 0:
   2955         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0;
   2956         break;
   2957     case 1U << 1:
   2958         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1;
   2959         break;
   2960     case 1U << 2:
   2961         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT;
   2962         break;
   2963     case 1U << 3:
   2964         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU;
   2965         break;
   2966     default:
   2967         break;
   2968     }
   2969 }
   2970 
   2971 void _phy_54618e_encode_syncout_mode(soc_port_phy_timesync_syncout_mode_t mode,
   2972                                      uint16 *value)
   2973 {
   2974     switch ( mode ) {
   2975     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE:
   2976         *value = 0x0;
   2977         break;
   2978     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME:
   2979         *value = 0x1;
   2980         break;
   2981     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN:
   2982         *value = 0x2;
   2983         break;
   2984     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC:
   2985         *value = 0x3;
   2986         break;
   2987     default:
   2988         break;
   2989     }
   2990 }
   2991 
   2992 void _phy_54618e_decode_syncout_mode(uint16 value,
   2993                                      soc_port_phy_timesync_syncout_mode_t *mode)
   2994 {
   2995     switch ( value & 0x3 ) {
   2996     case 0x0:
   2997         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE;
   2998         break;
   2999     case 0x1:
   3000         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME;
   3001         break;
   3002     case 0x2:
   3003         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN;
   3004         break;
   3005     case 0x3:
   3006         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC;
   3007         break;
   3008     }
   3009 }
   3010 
   3011 STATIC int
   3012 phy_54618_timesync_config_set(int unit, soc_port_t port,
   3013                               soc_port_phy_timesync_config_t *conf)
   3014 {
   3015     phy_ctrl_t *pc;
   3016     int         rv = SOC_E_NONE;
   3017     uint16      rx_control_reg = 0, tx_control_reg = 0, rx_crc_control_reg = 0,
   3018                 en_control_reg = 0, tx_capture_en_reg = 0, rx_capture_en_reg = 0,
   3019                 nse_nco_6 = 0, nse_nco_2c = 0, value, mask,
   3020                 gmode = 0, framesync_mode = 0, syncout_mode = 0,
   3021                 pulse_1_length, pulse_2_length, length_threshold, event_offset;
   3022     uint32      interval;
   3023 
   3024     pc = EXT_PHY_SW_STATE(unit, port);
   3025 
   3026     if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   3027         return SOC_E_UNAVAIL;
   3028     }
   3029 
   3030     do {
   3031         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) {
   3032 
   3033             if (conf->flags & SOC_PORT_PHY_TIMESYNC_ENABLE) {
   3034                 en_control_reg |= ((1U << 1) | (1U << 0));
   3035                 nse_nco_6 |= (1U << 12); /* NSE init */
   3036             }
   3037 
   3038             /* Top-Level Expansion Reg. 00h[1:0] IEEE 1588 Slice Enable Control */
   3039             SOC_IF_ERROR_BREAK
   3040                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x00, en_control_reg,
   3041                                                    0x3), rv);
   3042             /* Top-Level Expansion Reg. 03h[1:0]  1588 TX/RX SOP Timestamp Capture Enable */
   3043             if (conf->flags & SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE) {
   3044                 tx_capture_en_reg |= (1U <<  0);
   3045                 rx_capture_en_reg |= (1U <<  1);
   3046             }
   3047             SOC_IF_ERROR_BREAK
   3048                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x03,
   3049                         (tx_capture_en_reg | rx_capture_en_reg), 0x3), rv);
   3050 
   3051             /* Top-Level Expansion Register 31h[13:12]  NSE NCO Register 6 */
   3052             if (conf->flags & SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE) {
   3053                 nse_nco_6 |= (1U << 13);    /* TS_CAPTURE */
   3054             }
   3055             SOC_IF_ERROR_BREAK
   3056                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x31, nse_nco_6, 
   3057                                                    (0x3U << 12)), rv);
   3058 
   3059             /* Top-Level Expansion Register 14h: IEEE 1588 Tx/Rx CRC control register */
   3060             if (conf->flags & SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE) {
   3061                 rx_crc_control_reg |= (1U << 3);
   3062             }
   3063             SOC_IF_ERROR_BREAK
   3064                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x14, rx_crc_control_reg), rv);
   3065 
   3066             /* Top-Level Expansion Register 12h: IEEE 1588 Transmit/Receive Control Register */
   3067             if (conf->flags & SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE) {
   3068                 rx_control_reg |= (1U << 3);    /* RX_AS_EN */
   3069                 tx_control_reg |= (1U << 3);    /* TX_AS_EN */
   3070             }
   3071 
   3072             if (conf->flags & SOC_PORT_PHY_TIMESYNC_L2_ENABLE) {
   3073                 rx_control_reg |= (1U << 2);    /* RX_L2_EN */
   3074                 tx_control_reg |= (1U << 2);    /* TX_L2_EN */
   3075             }
   3076 
   3077             if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP4_ENABLE) {
   3078                 rx_control_reg |= (1U << 1);    /* RX_IPV4_UDP_EN */
   3079                 tx_control_reg |= (1U << 1);    /* TX_IPV4_UDP_EN */
   3080             }
   3081 
   3082             if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP6_ENABLE) {
   3083                 rx_control_reg |= (1U << 0);    /* RX_IPV6_UDP_EN */
   3084                 tx_control_reg |= (1U << 0);    /* TX_IPV6_UDP_EN */
   3085             }
   3086 
   3087             /* Top-Level Expansion Register 12h: IEEE 1588 Tx/Rx Control Register */
   3088             SOC_IF_ERROR_BREAK        /*  Rx[15:8] ,  Tx[7:0]  */ 
   3089                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x12,
   3090                                 ((rx_control_reg << 8) | tx_control_reg)), rv);
   3091 
   3092             /* Top-Level Expansion Register 26h[14]  NSE NCO Register 2-1 */
   3093             if (conf->flags & SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT) {
   3094                 nse_nco_2c &= (uint16) ~(1U << 14);
   3095             } else {
   3096                 nse_nco_2c |= (1U << 14);
   3097             }
   3098             SOC_IF_ERROR_BREAK       /* FREQ_mdio_sel[14] */
   3099                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x26, nse_nco_2c, 
   3100                                                (1U << 14)), rv);
   3101         }
   3102 
   3103         /* Top-Level Expansion Register 15h: VLAN1 Tags ITPID Register */
   3104         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) {
   3105             SOC_IF_ERROR_BREAK
   3106                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x15, conf->itpid), rv);
   3107         }
   3108 
   3109         /* Top-Level Expansion Register 16h: VLAN2 Tags OTPID Register */
   3110         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) {
   3111             SOC_IF_ERROR_BREAK
   3112                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x16, conf->otpid), rv);
   3113         }
   3114 
   3115         /* Top-Level Expansion Register 17h: VLAN2 Tags OTPID2 Register */
   3116         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) {
   3117             SOC_IF_ERROR_BREAK
   3118                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x17, conf->otpid2), rv);
   3119         }
   3120 
   3121         /* Top-Level Expansion Register 2Dh[11:0] NCO Register 4, nse_reg_ts_divider */
   3122         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) {
   3123             SOC_IF_ERROR_BREAK
   3124                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2d, conf->ts_divider & 0xfff), rv);
   3125         }
   3126 
   3127         /* Top-Level Expansion Register 5Ch/5Dh: Linkdelay1/2 */
   3128         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) {
   3129             SOC_IF_ERROR_BREAK
   3130                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x5c, conf->rx_link_delay & 0xffff), rv);
   3131             SOC_IF_ERROR_BREAK
   3132                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x5d, (conf->rx_link_delay >> 16) & 0xffff), rv);
   3133         }
   3134 
   3135         /* Top-Level Expansion Register 07h~0Bh: IEEE 1588 Original Time Code */
   3136         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) {
   3137             SOC_IF_ERROR_BREAK
   3138                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x07, (uint16)(conf->original_timecode.nanoseconds & 0xffff)), rv);
   3139 
   3140             SOC_IF_ERROR_BREAK
   3141                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x08, (uint16)((conf->original_timecode.nanoseconds >> 16) & 0xffff)), rv);
   3142 
   3143             SOC_IF_ERROR_BREAK
   3144                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x09, (uint16)(COMPILER_64_LO(conf->original_timecode.seconds) & 0xffff)), rv);
   3145 
   3146             SOC_IF_ERROR_BREAK
   3147                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x0a, (uint16)((COMPILER_64_LO(conf->original_timecode.seconds) >> 16) & 0xffff)), rv);
   3148 
   3149             SOC_IF_ERROR_BREAK
   3150                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x0b, (uint16)(COMPILER_64_HI(conf->original_timecode.seconds) & 0xffff)), rv);
   3151 
   3152         }
   3153         mask = 0;
   3154 
   3155         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) {
   3156             _phy_54618e_encode_gmode(conf->gmode,&gmode);
   3157             mask |= (0x3 << 14);
   3158         }
   3159 
   3160         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) {
   3161             _phy_54618e_encode_framesync_mode(conf->framesync.mode, &framesync_mode);
   3162             mask |= (0xf << 2) |  (0x1 << 11);
   3163 
   3164             /* Divide by 8 */
   3165             length_threshold = conf->framesync.length_threshold >> 3;
   3166             event_offset = conf->framesync.event_offset >> 3;
   3167 
   3168             /* Top-Level Expansion Register 32h, 1588 Length Threshold */
   3169             SOC_IF_ERROR_BREAK
   3170                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x32, length_threshold), rv);
   3171             /* Top-Level Expansion Register 33h, 1588 Event Offset */
   3172             SOC_IF_ERROR_BREAK
   3173                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x33, event_offset), rv);
   3174         }
   3175 
   3176         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) {
   3177             _phy_54618e_encode_syncout_mode(conf->syncout.mode, &syncout_mode);
   3178             mask |= (0x3 << 0);
   3179 
   3180             /* Divide by 8 */
   3181             interval = conf->syncout.interval >> 3;
   3182             pulse_1_length = conf->syncout.pulse_1_length >> 3; /* framesync pulse length */
   3183             pulse_2_length = conf->syncout.pulse_2_length >> 3; /* pulse train length */
   3184 
   3185             /* Top-Level Expansion Register 29h[15:0], 2Ah[13:0]. Interval_Length */
   3186             SOC_IF_ERROR_BREAK
   3187                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x29,
   3188                                                    interval & 0xffff), rv);
   3189             SOC_IF_ERROR_BREAK
   3190                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2a,
   3191                                                    (interval >> 16) & 0x3fff), rv);
   3192 
   3193             /* Top-Level Expansion Register 2bh[8:0], PULSE_TRAIN_length */
   3194             SOC_IF_ERROR_BREAK
   3195                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2b,
   3196                                                    (pulse_2_length & 0x1ff)), rv);
   3197             /* Top-Level Expansion Register 2ch[8:0], FRMSYNC_PULSE_length */
   3198             SOC_IF_ERROR_BREAK
   3199                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2c,
   3200                                                    (pulse_1_length & 0x1ff)), rv);
   3201 
   3202             /* Top-Level Expansion Register 2Eh~30h. Synout_ts_reg */
   3203             SOC_IF_ERROR_BREAK
   3204                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2e, 
   3205                     (uint16)(COMPILER_64_LO(conf->syncout.syncout_ts) & 0xffff)), rv);
   3206             SOC_IF_ERROR_BREAK
   3207                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x2f, 
   3208                     (uint16)((COMPILER_64_LO(conf->syncout.syncout_ts) >> 16) & 0xffff)), rv);
   3209             SOC_IF_ERROR_BREAK
   3210                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x30, 
   3211                     (uint16)(COMPILER_64_HI(conf->syncout.syncout_ts) & 0xffff)), rv);
   3212         }
   3213 
   3214         /* Top-Level Expansion Reg.31h,  NSE NCO Reg. 6 */
   3215         /*           GMODE[15:14], FRAMESYNC_MODE[5:2], SYNCOUT_mode[1:0] */
   3216         SOC_IF_ERROR_BREAK
   3217             (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x31, (gmode << 14) |
   3218                 ((framesync_mode & 0x2) ? (1U << 11) : (1U << 6)) | /* if bits 1 or 2 are set, turn off syncout */
   3219                 (framesync_mode << 2) | (syncout_mode << 0), mask), rv);
   3220 
   3221         /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */
   3222         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) {
   3223             value  = (uint16) (conf->tx_timestamp_offset & 0x0fff);       /* TS_OFFSET_TX[11:0] */
   3224             value |= (uint16)((conf->rx_timestamp_offset >> 4) & 0xf000); /* TS_OFFSET_RX_MSB[15:12] */
   3225             SOC_IF_ERROR_BREAK
   3226                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x05, value), rv);
   3227         }
   3228         /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */
   3229         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) {
   3230             SOC_IF_ERROR_BREAK
   3231                 (_phy_54618e_toplvl_exp_reg_write( unit, pc, 0, 0x06,
   3232                                        (uint16)(conf->rx_timestamp_offset & 0xffff) ), rv);
   3233         }
   3234 
   3235         /* Tx Event Message Mode Selection */
   3236         value = 0;
   3237         mask = 0;
   3238 
   3239         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) {
   3240             _phy_54618e_encode_egress_message_mode(conf->tx_sync_mode, 0, &value);
   3241             mask |= 0x3 << 0;
   3242         }
   3243         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) {
   3244             _phy_54618e_encode_egress_message_mode(conf->tx_delay_request_mode, 2, &value);
   3245             mask |= 0x3 << 2;
   3246         }
   3247         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) {
   3248             _phy_54618e_encode_egress_message_mode(conf->tx_pdelay_request_mode, 4, &value);
   3249             mask |= 0x3 << 4;
   3250         }
   3251         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) {
   3252             _phy_54618e_encode_egress_message_mode(conf->tx_pdelay_response_mode, 6, &value);
   3253             mask |= 0x3 << 6;
   3254         }
   3255 
   3256         /* Top-Level Expansion Register 01h: IEEE 1588 TX Event Message Mode Selection */
   3257         SOC_IF_ERROR_BREAK
   3258             (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x01, value, mask), rv); 
   3259 
   3260         /* Rx Event Message Mode Selection */
   3261         value = 0;
   3262         mask = 0;
   3263 
   3264         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) {
   3265             _phy_54618e_encode_ingress_message_mode(conf->rx_sync_mode, 0, &value);
   3266             mask |= 0x3 << 0;
   3267         }
   3268         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) {
   3269             _phy_54618e_encode_ingress_message_mode(conf->rx_delay_request_mode, 2, &value);
   3270             mask |= 0x3 << 2;
   3271         }
   3272         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) {
   3273             _phy_54618e_encode_ingress_message_mode(conf->rx_pdelay_request_mode, 4, &value);
   3274             mask |= 0x3 << 4;
   3275         }
   3276         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) {
   3277             _phy_54618e_encode_ingress_message_mode(conf->rx_pdelay_response_mode, 6, &value);
   3278             mask |= 0x3 << 6;
   3279         }
   3280 
   3281         /* Top-Level Expansion Register 02h: IEEE 1588 RX Event Message Mode Selection */
   3282         SOC_IF_ERROR_BREAK
   3283             (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x02, value, mask), rv); 
   3284 
   3285         /* Top-Level Expansion Register 19h~1Bh: NSE DPLL Register 2, REF_PHASE */
   3286         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) {
   3287             /* Initial ref phase [15:0] */
   3288             SOC_IF_ERROR_BREAK
   3289                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x19, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv);
   3290 
   3291             /* Initial ref phase [31:16]  */
   3292             SOC_IF_ERROR_BREAK
   3293                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1a, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) >> 16) & 0xffff)), rv);
   3294 
   3295             /* Initial ref phase [47:32] */
   3296             SOC_IF_ERROR_BREAK
   3297                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1b, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv);
   3298         }
   3299 
   3300         /* Top-Level Expansion Register 1Ch~1Dh: NSE DPLL Register 3, REF_PHASE_DELTA */
   3301         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) {
   3302             /* Ref phase delta [15:0] */
   3303             SOC_IF_ERROR_BREAK
   3304                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1c, (uint16)(conf->phy_1588_dpll_ref_phase_delta & 0xffff)), rv);
   3305 
   3306             /* Ref phase delta [31:16]  */
   3307             SOC_IF_ERROR_BREAK
   3308                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1d, (uint16)((conf->phy_1588_dpll_ref_phase_delta >> 16) & 0xffff)), rv);
   3309         }
   3310 
   3311         /* DPLL K1 & K2 */
   3312         mask = 0;
   3313         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) {
   3314             mask |= 0xff;         /* bit[7:0]   */
   3315         }
   3316         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) {
   3317             mask |= 0xff << 8;    /* bit[15:8] */
   3318         }
   3319         if ( mask != 0 ) {
   3320             /* Top-Level Expansion Register 1Eh: NSE DPLL K1/K2 */
   3321             SOC_IF_ERROR_BREAK
   3322                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x1e, (conf->phy_1588_dpll_k1 & 0xff)<<8 | (conf->phy_1588_dpll_k2 & 0xff), mask ), rv);
   3323         }
   3324 
   3325         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) {
   3326             /* Top-Level Expansion Register 1Fh: NSE DPLL K3 */
   3327             SOC_IF_ERROR_BREAK
   3328                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x1f, conf->phy_1588_dpll_k3 & 0xff), rv);
   3329         }
   3330 
   3331         /* Top-Level Expansion Register 20h~23h: NSE DPLL Register 7, LOOP_FILTER */
   3332         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) {
   3333             /* Initial loop filter[15:0] */
   3334             SOC_IF_ERROR_BREAK
   3335                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x20, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv);
   3336 
   3337             /* Initial loop filter[31:16]  */
   3338             SOC_IF_ERROR_BREAK
   3339                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x21, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv);
   3340 
   3341             /*  Initial loop filter[47:32] */
   3342             SOC_IF_ERROR_BREAK
   3343                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x22, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv);
   3344 
   3345             /* Initial loop filter[63:48]  */
   3346             SOC_IF_ERROR_BREAK
   3347                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x23, (uint16)((COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv);
   3348         }
   3349     } while ( 0 );
   3350 
   3351     return SOC_E_NONE;
   3352 }
   3353 
   3354 STATIC int
   3355 phy_54618_timesync_config_get(int unit, soc_port_t port,
   3356                               soc_port_phy_timesync_config_t *conf)
   3357 {
   3358     int    rv = SOC_E_NONE;
   3359     uint16 tx_control_reg = 0, rx_crc_control_reg = 0,
   3360            en_control_reg = 0, tx_capture_en_reg = 0,
   3361            nse_nco_6 = 0, nse_nco_2c = 0, temp1, temp2, temp3, temp4, value;
   3362     phy_ctrl_t *pc;
   3363     soc_port_phy_timesync_global_mode_t gmode = SOC_PORT_PHY_TIMESYNC_MODE_FREE;
   3364     soc_port_phy_timesync_framesync_mode_t framesync_mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_NONE;
   3365     soc_port_phy_timesync_syncout_mode_t syncout_mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE;
   3366 
   3367     pc = EXT_PHY_SW_STATE(unit, port);
   3368 
   3369     if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   3370         return SOC_E_UNAVAIL;
   3371     }
   3372     conf->flags = 0;
   3373 
   3374     do {
   3375         /* Top-Level Expansion Register 31h  NSE NCO Register 6 */
   3376         SOC_IF_ERROR_BREAK
   3377             (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x31, &nse_nco_6), rv);
   3378 
   3379         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) {
   3380             /* Top-Level Expansion Reg. 00h[1:0] IEEE 1588 Slice Enable Control */
   3381             SOC_IF_ERROR_BREAK
   3382                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x00, &en_control_reg), rv); 
   3383 
   3384             if (en_control_reg & (1U << 0)) {
   3385                 conf->flags |= SOC_PORT_PHY_TIMESYNC_ENABLE;
   3386             }
   3387 
   3388             /* Top-Level Expansion Reg. 03h[1:0]  1588 Rx/Tx SOP Timestamp Capture Enable */
   3389             SOC_IF_ERROR_BREAK
   3390                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x03, &tx_capture_en_reg), rv); 
   3391             if (tx_capture_en_reg & (1U << 0)) {    /* bit[0] Tx TS Capture Enable */
   3392                 conf->flags |= SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE;
   3393             }
   3394 
   3395             if (nse_nco_6 & (1U << 13)) {    /* TopLvl Exp. 31h[13]: TS_CAPTURE */
   3396                 conf->flags |= SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE;
   3397             }
   3398 
   3399             /* Top-Level Expansion Register 14h: IEEE 1588 Tx/Rx CRC control register */
   3400             SOC_IF_ERROR_BREAK
   3401                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x14, &rx_crc_control_reg), rv);
   3402 
   3403             if (rx_crc_control_reg & (1U << 3)) {
   3404                 conf->flags |= SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE;
   3405             }
   3406 
   3407             /* Top-Level Expansion Register 12h: IEEE 1588 Tx/Rx Control Register */
   3408             SOC_IF_ERROR_BREAK
   3409                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x12, &tx_control_reg), rv);
   3410                                               
   3411             if (tx_control_reg & (1U << 3)) {
   3412                 conf->flags |= SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE;
   3413             }
   3414 
   3415             if (tx_control_reg & (1U << 2)) {
   3416                 conf->flags |= SOC_PORT_PHY_TIMESYNC_L2_ENABLE;
   3417             }
   3418 
   3419             if (tx_control_reg & (1U << 1)) {
   3420                 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP4_ENABLE;
   3421             }
   3422 
   3423             if (tx_control_reg & (1U << 0)) {
   3424                 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP6_ENABLE;
   3425             }
   3426 
   3427             /* Top-Level Expansion Register 26h[14]  NSE NCO Register 2-1 */
   3428             SOC_IF_ERROR_BREAK
   3429                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x26, &nse_nco_2c), rv);
   3430 
   3431             if (!(nse_nco_2c & (1U << 14))) {    /* FREQ_mdio_sel[14] */
   3432                 conf->flags |= SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT;
   3433             }
   3434         }
   3435 
   3436         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) {
   3437             _phy_54618e_decode_gmode((nse_nco_6  >> 14),&gmode);
   3438             conf->gmode = gmode;
   3439         }
   3440 
   3441         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) {
   3442             _phy_54618e_decode_framesync_mode((nse_nco_6  >> 2), &framesync_mode);
   3443             conf->framesync.mode = framesync_mode;
   3444             /* Top-Level Expansion Register 32h, 1588 Length Threshold */
   3445             SOC_IF_ERROR_BREAK
   3446                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x32, &temp1), rv);
   3447             /* Top-Level Expansion Register 33h, 1588 Event Offset */
   3448             SOC_IF_ERROR_BREAK
   3449                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x33, &temp2), rv);
   3450 
   3451             /* Multiply by 8 */
   3452             conf->framesync.length_threshold = temp1 << 3;
   3453             conf->framesync.event_offset     = temp2 << 3;
   3454         }
   3455 
   3456         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) {
   3457             _phy_54618e_decode_syncout_mode((nse_nco_6  >> 0), &syncout_mode);
   3458             conf->syncout.mode = syncout_mode;
   3459 
   3460             /* Top-Level Expansion Register 29h[15:0], 2Ah[13:0]. Interval_Length */
   3461             SOC_IF_ERROR_BREAK
   3462                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x29, &temp1), rv);
   3463             SOC_IF_ERROR_BREAK
   3464                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2a, &temp2), rv);
   3465             conf->syncout.interval =  ((temp2 & 0x3ff)<< 16) | temp1;
   3466 
   3467             /* Top-Level Expansion Register 2bh[8:0], PULSE_TRAIN_length */
   3468             SOC_IF_ERROR_BREAK
   3469                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2b, &temp2), rv);
   3470             /* Top-Level Expansion Register 2ch[8:0], FRMSYNC_PULSE_length */
   3471             SOC_IF_ERROR_BREAK
   3472                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2c, &temp1), rv);
   3473 
   3474             /* Multiply by 8  (unit = 8ns) */
   3475             conf->syncout.pulse_1_length = (temp1 & 0x1ff) << 3;  /* FrmSync pulse length */
   3476             conf->syncout.pulse_2_length = (temp2 & 0x1ff) << 3;    /* pulse train length */
   3477 
   3478             /* Top-Level Expansion Register 2Eh~30h. Synout_ts_reg (48 bits) */
   3479             SOC_IF_ERROR_BREAK
   3480                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2e, &temp1), rv);
   3481             SOC_IF_ERROR_BREAK
   3482                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2f, &temp2), rv);
   3483             SOC_IF_ERROR_BREAK
   3484                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x30, &temp3), rv);
   3485 
   3486             COMPILER_64_SET( conf->syncout.syncout_ts, (uint32) temp3,
   3487                              ((uint32) temp2 << 16) | ((uint32) temp1) );
   3488         }
   3489 
   3490         /* Top-Level Expansion Register 15h: VLAN1 Tags ITPID Register */
   3491         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) {
   3492             SOC_IF_ERROR_BREAK
   3493                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x15, &conf->itpid), rv);
   3494         }
   3495 
   3496         /* Top-Level Expansion Register 16h: VLAN2 Tags OTPID Register */
   3497         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) {
   3498             SOC_IF_ERROR_BREAK
   3499                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x16, &conf->otpid), rv);
   3500         }
   3501 
   3502         /* Top-Level Expansion Register 17h: VLAN2 Tags OTPID2 Register */
   3503         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) {
   3504             SOC_IF_ERROR_BREAK
   3505                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x17, &conf->otpid2), rv);
   3506         }
   3507 
   3508         /* Top-Level Expansion Register 2Dh[11:0] NCO Register 4, nse_reg_ts_divider */
   3509         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) {
   3510             SOC_IF_ERROR_BREAK
   3511                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x2d, &conf->ts_divider), rv);
   3512         }
   3513 
   3514         /* Top-Level Expansion Register 5Ch/5Dh: Linkdelay1/2 */
   3515         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) {
   3516             SOC_IF_ERROR_BREAK
   3517                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x5c, &temp1), rv);
   3518             SOC_IF_ERROR_BREAK
   3519                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x5d, &temp2), rv);
   3520 
   3521             conf->rx_link_delay = ((uint32)temp2 << 16) | temp1; 
   3522         }
   3523 
   3524         /* Top-Level Expansion Register 07h~0Bh: IEEE 1588 Original Time Code */
   3525         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) {
   3526             SOC_IF_ERROR_BREAK
   3527                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x07, &temp1), rv);
   3528 
   3529             SOC_IF_ERROR_BREAK
   3530                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x08, &temp2), rv);
   3531 
   3532             conf->original_timecode.nanoseconds = ((uint32)temp2 << 16) | temp1; 
   3533 
   3534             SOC_IF_ERROR_BREAK
   3535                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x09, &temp1), rv);
   3536 
   3537             SOC_IF_ERROR_BREAK
   3538                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x0a, &temp2), rv);
   3539 
   3540             SOC_IF_ERROR_BREAK
   3541                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x0b, &temp3), rv);
   3542 
   3543             COMPILER_64_SET(conf->original_timecode.seconds, ((uint32)temp3),  (((uint32)temp2<<16)|((uint32)temp1)));
   3544         }
   3545 
   3546         /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */
   3547         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) {
   3548             SOC_IF_ERROR_BREAK
   3549                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x05, &temp2), rv);
   3550             conf->tx_timestamp_offset = temp2 & 0x0fff;
   3551         }
   3552 
   3553         /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */
   3554         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) {
   3555             SOC_IF_ERROR_BREAK
   3556                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x06, &temp1), rv);
   3557             conf->rx_timestamp_offset  = (uint32) temp1;                    /* TS_OFFSET_RX[15:0] */
   3558             conf->rx_timestamp_offset |= ((uint32) (temp2 & 0xf000)) << 4 ; /* TS_OFFSET_RX_MSB[15:12] */
   3559         }
   3560 
   3561         /* Top-Level Expansion Register 01h: IEEE 1588 TX Event Message Mode Selection */
   3562         SOC_IF_ERROR_BREAK
   3563             (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x01, &value), rv); 
   3564 
   3565         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) {
   3566             _phy_54618e_decode_egress_message_mode(value, 0, &conf->tx_sync_mode);
   3567         }
   3568 
   3569         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) {
   3570             _phy_54618e_decode_egress_message_mode(value, 2, &conf->tx_delay_request_mode);
   3571         }
   3572 
   3573         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) {
   3574             _phy_54618e_decode_egress_message_mode(value, 4, &conf->tx_pdelay_request_mode);
   3575         }
   3576 
   3577         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) {
   3578             _phy_54618e_decode_egress_message_mode(value, 6, &conf->tx_pdelay_response_mode);
   3579         }
   3580 
   3581         /* Top-Level Expansion Register 02h: IEEE 1588 RX Event Message Mode Selection */
   3582         SOC_IF_ERROR_BREAK
   3583             (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x02, &value), rv); 
   3584 
   3585         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) {
   3586             _phy_54618e_decode_ingress_message_mode(value, 0, &conf->rx_sync_mode);
   3587         }
   3588 
   3589         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) {
   3590             _phy_54618e_decode_ingress_message_mode(value, 2, &conf->rx_delay_request_mode);
   3591         }
   3592 
   3593         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) {
   3594             _phy_54618e_decode_ingress_message_mode(value, 4, &conf->rx_pdelay_request_mode);
   3595         }
   3596 
   3597         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) {
   3598             _phy_54618e_decode_ingress_message_mode(value, 6, &conf->rx_pdelay_response_mode);
   3599         }
   3600 
   3601         /* Top-Level Expansion Register 19h~1Bh: NSE DPLL Register 2, REF_PHASE */
   3602         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) {
   3603             /* Initial ref phase [15:0] */
   3604             SOC_IF_ERROR_BREAK
   3605                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x19, &temp1), rv);
   3606 
   3607             /* Initial ref phase [31:16]  */
   3608             SOC_IF_ERROR_BREAK
   3609                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1a, &temp2), rv);
   3610 
   3611             /*  Initial ref phase [47:32] */
   3612             SOC_IF_ERROR_BREAK
   3613                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1b, &temp3), rv);
   3614 
   3615             COMPILER_64_SET(conf->phy_1588_dpll_ref_phase, ((uint32)temp3), (((uint32)temp2<<16)|((uint32)temp1)));
   3616         }
   3617 
   3618         /* Top-Level Expansion Register 1Ch~1Dh: NSE DPLL Register 3, REF_PHASE_DELTA */
   3619         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) {
   3620             /* Ref phase delta [15:0] */
   3621             SOC_IF_ERROR_BREAK
   3622                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1c, &temp1), rv);
   3623 
   3624             /* Ref phase delta [31:16]  */
   3625             SOC_IF_ERROR_BREAK
   3626                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1d, &temp2), rv);
   3627 
   3628             conf->phy_1588_dpll_ref_phase_delta = (temp2 << 16) | temp1;
   3629         }
   3630 
   3631         /* Top-Level Expansion Register 1Eh: NSE DPLL K1/K2 */
   3632         SOC_IF_ERROR_BREAK
   3633             (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1e, &temp1 ), rv);
   3634 
   3635         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) {
   3636             conf->phy_1588_dpll_k1 = (temp1 >> 8 ) & 0xff;
   3637         }
   3638 
   3639         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) {
   3640             conf->phy_1588_dpll_k2 = temp1 & 0xff;
   3641         }
   3642 
   3643         /* Top-Level Expansion Register 1Fh: NSE DPLL K3 */
   3644         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) {
   3645             SOC_IF_ERROR_BREAK
   3646                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x1f, &temp1), rv);
   3647             conf->phy_1588_dpll_k3 = temp1 & 0xff;
   3648         }
   3649 
   3650         /* Top-Level Expansion Register 20h~23h: NSE DPLL Register 7, LOOP_FILTER */
   3651         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) {
   3652             /* Initial loop filter[15:0] */
   3653             SOC_IF_ERROR_BREAK
   3654                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x20, &temp1), rv);
   3655 
   3656             /* Initial loop filter[31:16]  */
   3657             SOC_IF_ERROR_BREAK
   3658                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x21, &temp2), rv);
   3659 
   3660             /*  Initial loop filter[47:32] */
   3661             SOC_IF_ERROR_BREAK
   3662                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x22, &temp3), rv);
   3663 
   3664             /* Initial loop filter[63:48]  */
   3665             SOC_IF_ERROR_BREAK
   3666                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x23, &temp4), rv);
   3667 
   3668             COMPILER_64_SET(conf->phy_1588_dpll_loop_filter, (((uint32)temp4<<16)|((uint32)temp3)), (((uint32)temp2<<16)|((uint32)temp1)));
   3669         }
   3670     } while ( 0 );
   3671                                               
   3672     return SOC_E_NONE;
   3673 }
   3674 
   3675 STATIC int
   3676 phy_54618_timesync_control_set(int unit, soc_port_t port,
   3677                                soc_port_control_phy_timesync_t type, uint64 value)
   3678 {
   3679     uint16       temp1, temp2;
   3680     uint32       value0;
   3681     int          rv = SOC_E_NONE;
   3682     phy_ctrl_t  *pc;
   3683 
   3684     pc = EXT_PHY_SW_STATE(unit, port);
   3685 
   3686     if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   3687         return SOC_E_UNAVAIL;
   3688     }
   3689 
   3690     do {
   3691         switch ( type ) {
   3692         case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP:
   3693         case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP:
   3694             return SOC_E_UNAVAIL;
   3695 
   3696         case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND:
   3697             value0 = COMPILER_64_LO(value);    /* nse_reg_nco_freqcntrl[31:0] */
   3698             /* Top-Level Expansion Register 24h~25h: NSE NCO Register 1, NSE_REQ_NCO_FREQCNTRL */
   3699             SOC_IF_ERROR_BREAK                 /* nse_reg_nco_freqcntrl[15:0]  LSB */
   3700                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x24, (uint16) (value0 & 0xffff)), rv);
   3701             SOC_IF_ERROR_BREAK                 /* nse_reg_nco_freqcntrl[31:16] MSB */
   3702                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x25, (uint16) ((value0 >> 16) & 0xffff)), rv);
   3703             break;
   3704 
   3705         case SOC_PORT_CONTROL_PHY_TIMESYNC_FRAMESYNC:
   3706             /* Top-Level Expansion Register 31h  NSE NCO Register 6 */
   3707             SOC_IF_ERROR_BREAK
   3708                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x31, &temp1), rv);
   3709             temp2 = ((temp1 | (0x3 << 14) | (0x1 << 12)) & ~(0xf << 2)) | (0x1 << 5);
   3710             SOC_IF_ERROR_BREAK
   3711                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x31, temp2), rv);
   3712             sal_udelay(1);
   3713             temp2 &= ~((0x1 << 5) | (0x1 << 12));
   3714             SOC_IF_ERROR_BREAK
   3715                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x31, temp2), rv);
   3716             sal_udelay(1);
   3717             SOC_IF_ERROR_BREAK
   3718                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x31, temp1), rv);
   3719 
   3720             break;
   3721 
   3722         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME:
   3723             COMPILER_64_SHR(value, 4);
   3724             /* Top-Level Expansion Register 26h~28h  NSE NCO Register 2, Local Time */
   3725             SOC_IF_ERROR_BREAK
   3726                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x28, (uint16)(COMPILER_64_LO(value) & 0xffff)), rv);
   3727             SOC_IF_ERROR_BREAK
   3728                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x27, (uint16)((COMPILER_64_LO(value) >> 16) & 0xffff)), rv);
   3729             SOC_IF_ERROR_BREAK
   3730                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x26, (uint16)(COMPILER_64_HI(value) & 0x0fff), 0x0fff), rv);
   3731             break;
   3732 
   3733         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL:
   3734             temp1 = 0;
   3735             temp2 = 0;
   3736             value0 = COMPILER_64_LO(value);
   3737 
   3738             if (value0 &  SOC_PORT_PHY_TIMESYNC_TN_LOAD) {
   3739                 temp1 |= 1U << 11;
   3740             }
   3741             if (value0 &  SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD) {
   3742                 temp2 |= 1U << 11;
   3743             }
   3744             if (value0 &  SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD) {
   3745                 temp1 |= 1U << 10;
   3746             }
   3747             if (value0 &  SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD) {
   3748                 temp2 |= 1U << 10;
   3749             }
   3750             if (value0 &  SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD) {
   3751                 temp1 |= 1U << 9;
   3752             }
   3753             if (value0 &  SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD) {
   3754                 temp2 |= 1U << 9;
   3755             }
   3756             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD) {
   3757                 temp1 |= 1U << 8;
   3758             }
   3759             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD) {
   3760                 temp2 |= 1U << 8;
   3761             }
   3762             if (value0 &  SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD) {
   3763                 temp1 |= 1U << 7;
   3764             }
   3765             if (value0 &  SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD) {
   3766                 temp2 |= 1U << 7;
   3767             }
   3768             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD) {
   3769                 temp1 |= 1U << 6;
   3770             }
   3771             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD) {
   3772                 temp2 |= 1U << 6;
   3773             }
   3774             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD) {
   3775                 temp1 |= 1U << 5;
   3776             }
   3777             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD) {
   3778                 temp2 |= 1U << 5;
   3779             }
   3780             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD) {
   3781                 temp1 |= 1U << 4;
   3782             }
   3783             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD) {
   3784                 temp2 |= 1U << 4;
   3785             }
   3786             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD) {
   3787                 temp1 |= 1U << 3;
   3788             }
   3789             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD) {
   3790                 temp2 |= 1U << 3;
   3791             }
   3792             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD) {
   3793                 temp1 |= 1U << 2;
   3794             }
   3795             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD) {
   3796                 temp2 |= 1U << 2;
   3797             }
   3798             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD) {
   3799                 temp1 |= 1U << 1;
   3800             }
   3801             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD) {
   3802                 temp2 |= 1U << 1;
   3803             }
   3804             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD) {
   3805                 temp1 |= 1U << 0;
   3806             }
   3807             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD) {
   3808                 temp2 |= 1U << 0;
   3809             }
   3810             /* Top-Level Expansion Register 0Fh: IEEE 1588 Shadow Register Control */
   3811             SOC_IF_ERROR_BREAK
   3812                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x0f, temp1), rv);
   3813             /* Top-Level Expansion Register 10h: IEEE 1588 Shadow Register Load */
   3814             SOC_IF_ERROR_BREAK
   3815                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x10, temp2), rv);
   3816             break;
   3817 
   3818         case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK:
   3819             temp1 = 0;
   3820             value0 = COMPILER_64_LO(value);
   3821 
   3822             if (value0 &  SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK) {
   3823                 temp1 |= 1U << 9;    /* bit[9] INTC_SOP_MASK */
   3824             }
   3825             if (value0 &  SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK) {
   3826                 temp1 |= 1U << 8;    /* bit[8] INTC_FSYNC_MASK */
   3827             }
   3828             /* Top-Level Expansion Register 11h: IEEE 1588 Interrupt/Interrupt Mask */
   3829             SOC_IF_ERROR_BREAK
   3830                 (_phy_54618e_toplvl_exp_reg_write(unit, pc, 0, 0x11, temp1), rv);
   3831             break;
   3832 
   3833         case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET:
   3834             value0 = COMPILER_64_LO(value);
   3835 
   3836             /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */
   3837             SOC_IF_ERROR_BREAK
   3838                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x05, (uint16)(value0 & 0x0fff), 0x0fff), rv);
   3839             break;
   3840 
   3841         case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET:
   3842             value0 = COMPILER_64_LO(value);
   3843 
   3844             /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */
   3845             SOC_IF_ERROR_BREAK
   3846                 (_phy_54618e_toplvl_exp_reg_modify(unit, pc, 0, 0x05, (uint16)(value0 & 0xf000), 0xf000), rv);
   3847             SOC_IF_ERROR_BREAK
   3848                 (_phy_54618e_toplvl_exp_reg_write( unit, pc, 0, 0x06, (uint16)(value0 & 0xffff)), rv);
   3849 
   3850             break;
   3851 
   3852         default:
   3853             return SOC_E_UNAVAIL;
   3854         }
   3855     } while ( 0 );
   3856 
   3857     return SOC_E_NONE;
   3858 }
   3859 
   3860 STATIC int
   3861 phy_54618_timesync_control_get(int unit, soc_port_t port,
   3862                                soc_port_control_phy_timesync_t type, uint64 *value)
   3863 {
   3864     uint16       value0, value1, value2;
   3865     int          rv = SOC_E_NONE;
   3866     phy_ctrl_t  *pc;
   3867 
   3868     pc = EXT_PHY_SW_STATE(unit, port);
   3869     if ( ! PHY_IS_BCM54618SE_OR_BCM54618E(pc) ) {
   3870         return SOC_E_UNAVAIL;
   3871     }
   3872 
   3873     do {
   3874         switch ( type ) {
   3875         case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP:
   3876             /* Start a Heartbeat Read. Expansion Reg. F3h[0], Heartbeat_Start=1 */
   3877             SOC_IF_ERROR_BREAK
   3878                 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x1), rv);
   3879 
   3880             /* Top-Level Expansion Register 57h~55h: Heartbeat Timestamp (48 bits) */
   3881             SOC_IF_ERROR_BREAK
   3882                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x55, &value0), rv);
   3883             SOC_IF_ERROR_BREAK
   3884                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x56, &value1), rv);
   3885             SOC_IF_ERROR_BREAK
   3886                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x57, &value2), rv);
   3887 
   3888             /* Stop a Heartbeat Read. Expansion Reg. F3h[1], Heartbeat_Stop=1 */
   3889             SOC_IF_ERROR_BREAK
   3890                 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x2), rv);
   3891             SOC_IF_ERROR_BREAK
   3892                 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv);
   3893 
   3894             COMPILER_64_SET((*value), ((uint32)value2), (((uint32)value1<<16) | ((uint32)value0)));
   3895             /*  *value =  (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */
   3896             break;
   3897 
   3898         case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP:
   3899             /* Start a Timestamp Read. Expansion Reg. F3h[2], TS_START=1 */
   3900             SOC_IF_ERROR_BREAK
   3901                 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x4), rv);
   3902 
   3903             /* Top-Level Expansion Register 52h~50h: SOP Timestamp (48 bits) */
   3904             SOC_IF_ERROR_BREAK
   3905                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x50, &value0), rv);
   3906             SOC_IF_ERROR_BREAK
   3907                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x51, &value1), rv);
   3908             SOC_IF_ERROR_BREAK
   3909                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x52, &value2), rv);
   3910 
   3911             /* Start a Timestamp Read. Expansion Reg. F3h[3], TS_END=1 */
   3912             SOC_IF_ERROR_BREAK
   3913                 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x8), rv);
   3914             SOC_IF_ERROR_BREAK
   3915                 (WRITE_PHY54618_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv);
   3916 
   3917             COMPILER_64_SET((*value), ((uint32)value2), (((uint32)value1<<16) | ((uint32)value0)));
   3918             /*  *value =  (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */
   3919             break;
   3920 
   3921         case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND:
   3922             /* Top-Level Expansion Register 24h~25h: NSE NCO Register 1, NSE_REQ_NCO_FREQCNTRL */
   3923             SOC_IF_ERROR_BREAK
   3924                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x24, &value0), rv);
   3925             SOC_IF_ERROR_BREAK
   3926                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x25, &value1), rv);
   3927             COMPILER_64_SET( (*value), 0,  ((uint32)value1 << 16) | (uint32)value0 );
   3928             break;
   3929 
   3930         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME:
   3931             /* Top-Level Expansion Register 26h~28h  NSE NCO Register 2, Local Time (44 bits) */
   3932             SOC_IF_ERROR_BREAK
   3933                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x28, &value0), rv);
   3934             SOC_IF_ERROR_BREAK
   3935                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x27, &value1), rv);
   3936             SOC_IF_ERROR_BREAK
   3937                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x26, &value2), rv);
   3938             /*  Local_Time_MSB             [43:32]               [31:16]          [15:0] */
   3939             COMPILER_64_SET((*value), (value2 & 0x0fff), ((uint32)value1 << 16) | value0 );
   3940             COMPILER_64_SHL((*value), 4);
   3941             break;
   3942 
   3943         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL:
   3944             /* Top-Level Expansion Register 0Fh: IEEE 1588 Shadow Register Control */
   3945             SOC_IF_ERROR_BREAK
   3946                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x0f, &value1), rv);
   3947             /* Top-Level Expansion Register 10h: IEEE 1588 Shadow Register Load */
   3948             SOC_IF_ERROR_BREAK
   3949                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x10, &value2), rv);
   3950 
   3951             value0 = 0;
   3952             if (value1 & (1U << 11)) {
   3953                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_LOAD;
   3954             }
   3955             if (value2 & (1U << 11)) {
   3956                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD;
   3957             }
   3958             if (value1 & (1U << 10)) {
   3959                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD;
   3960             }
   3961             if (value2 & (1U << 10)) {
   3962                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD;
   3963             }
   3964             if (value1 & (1U << 9)) {
   3965                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD;
   3966             }
   3967             if (value2 & (1U << 9)) {
   3968                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD;
   3969             }
   3970             if (value1 & (1U << 8)) {
   3971                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD;
   3972             }
   3973             if (value1 & (1U << 8)) {
   3974                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD;
   3975             }
   3976             if (value1 & (1U << 7)) {
   3977                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD;
   3978             }
   3979             if (value1 & (1U << 7)) {
   3980                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD;
   3981             }
   3982             if (value1 & (1U << 6)) {
   3983                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD;
   3984             }
   3985             if (value2 & (1U << 6)) {
   3986                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD;
   3987             }
   3988             if (value1 & (1U << 5)) {
   3989                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD;
   3990             }
   3991             if (value2 & (1U << 5)) {
   3992                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD;
   3993             }
   3994             if (value1 & (1U << 4)) {
   3995                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD;
   3996             }
   3997             if (value2 & (1U << 4)) {
   3998                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD;
   3999             }
   4000             if (value1 & (1U << 3)) {
   4001                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD;
   4002             }
   4003             if (value2 & (1U << 3)) {
   4004                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD;
   4005             }
   4006             if (value1 & (1U << 2)) {
   4007                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD;
   4008             }
   4009             if (value2 & (1U << 2)) {
   4010                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD;
   4011             }
   4012             if (value1 & (1U << 1)) {
   4013                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD;
   4014             }
   4015             if (value2 & (1U << 1)) {
   4016                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD;
   4017             }
   4018             if (value1 & (1U << 0)) {
   4019                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD;
   4020             }
   4021             if (value2 & (1U << 0)) {
   4022                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD;
   4023             }
   4024             COMPILER_64_SET((*value), 0, (uint32)value0);
   4025             break;
   4026 
   4027         case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT:
   4028             /* Top-Level Expansion Register 11h: IEEE 1588 Interrupt/Interrupt Mask */
   4029             SOC_IF_ERROR_BREAK
   4030                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x11, &value1), rv);
   4031             value0 = 0;
   4032             if (value1 & (1U << 1)) {        /* bit[1] INTC_SOP */
   4033                 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT;
   4034             }
   4035             if (value1 & (1U << 0)) {        /* bit[0] INTC_FSYNC */
   4036                 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT;
   4037             }
   4038             COMPILER_64_SET((*value), 0, (uint32)value0);
   4039             break;
   4040 
   4041         case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK:
   4042             /* Top-Level Expansion Register 11h: IEEE 1588 Interrupt/Interrupt Mask */
   4043             SOC_IF_ERROR_BREAK
   4044                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x11, &value1), rv);
   4045             value0 = 0;
   4046             if (value1 & (1U << 9)) {        /* bit[9] INTC_SOP_MASK */
   4047                 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK;
   4048             }
   4049             if (value1 & (1U << 8)) {        /* bit[8] INTC_FSYNC_MASK */
   4050                 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK;
   4051             }
   4052             COMPILER_64_SET((*value), 0, (uint32)value0);
   4053             break;
   4054 
   4055         case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET:
   4056             /* Top-Level Expansion Register 05h[11:0] IEEE 1588 Tx Timestamp Offset */
   4057             SOC_IF_ERROR_BREAK
   4058                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x05, &value0), rv);
   4059             COMPILER_64_SET((*value), 0, ((uint32)value0 & 0x0fff));
   4060             break;
   4061 
   4062         case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET:
   4063             /* Top-Level Expansion Register 05h[15:12]+06h[15:0] IEEE 1588 Rx Timestamp Offset */
   4064             SOC_IF_ERROR_BREAK                          /* TS_OFFSET_RX_MSB[15:12] */
   4065                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x05, &value1), rv);
   4066             SOC_IF_ERROR_BREAK                          /* TS_OFFSET_RX[15:0] */
   4067                 (_phy_54618e_toplvl_exp_reg_read(unit, pc, 0, 0x06, &value0), rv);
   4068             COMPILER_64_SET((*value), 0, (((uint32)value1 & 0xf000) << 4) | value0);
   4069             break;
   4070 
   4071         default:
   4072             return SOC_E_UNAVAIL;
   4073         }
   4074     } while ( 0 );
   4075 
   4076     return SOC_E_NONE;
   4077 }
   4078 
   4079 
   4080 /*
   4081  * Function:
   4082  *      phy_54616_probe
   4083  * Purpose:
   4084  *      Complement the generic phy probe routine to identify this phy when its
   4085  *      phy id0 and id1 is same as some other phy's.
   4086  * Parameters:
   4087  *      unit - StrataSwitch unit #.
   4088  *      pc   - phy ctrl descriptor.
   4089  * Returns:
   4090  *      SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error>
   4091  */
   4092 STATIC int
   4093 phy_54616_probe(int unit, phy_ctrl_t *pc)
   4094 {
   4095     uint16 id0, id1, data;
   4096     soc_phy_info_t *pi;
   4097 
   4098     if (READ_PHY54616_MII_PHY_ID0r(unit, pc, &id0) < 0) {
   4099         return SOC_E_NOT_FOUND;
   4100     }
   4101     if (READ_PHY54616_MII_PHY_ID1r(unit, pc, &id1) < 0) {
   4102         return SOC_E_NOT_FOUND;
   4103     }
   4104 
   4105     pi = &SOC_PHY_INFO(unit, pc->port);
   4106 
   4107     switch (PHY_MODEL(id0, id1)) {
   4108     case PHY_BCM54616_MODEL:
   4109         SOC_IF_ERROR_RETURN
   4110             (READ_PHY54616_MODE_CTRLr(unit, pc, &data));
   4111         if (data & (1U << 3)) {
   4112             /* Serdes present so it's a 54616S */
   4113             pi->phy_name = "BCM54616S";
   4114             PHY_FLAGS_SET(pc->unit, pc->port, PHY_FLAGS_SECONDARY_SERDES);
   4115         }
   4116         break;
   4117 
   4118     case PHY_BCM54618E_MODEL:
   4119     case PHY_BCM54618SE_MODEL:
   4120         return SOC_E_NONE;
   4121 
   4122     default:
   4123         return SOC_E_NOT_FOUND;
   4124     }
   4125 
   4126     return SOC_E_NONE;
   4127 }
   4128 
   4129 
   4130 #ifdef BROADCOM_DEBUG
   4131 
   4132 /*
   4133  * Function:
   4134  *      phy_54616_shadow_dump
   4135  * Purpose:
   4136  *      Debug routine to dump all shadow registers.
   4137  * Parameters:
   4138  *      unit - StrataSwitch unit #.
   4139  *      port - StrataSwitch port #.
   4140  */
   4141 
   4142 void
   4143 phy_54616_shadow_dump(int unit, soc_port_t port)
   4144 {
   4145     phy_ctrl_t *pc;
   4146     uint16      tmp;
   4147     int         i;
   4148 
   4149     pc       = EXT_PHY_SW_STATE(unit, port);
   4150 
   4151     /* Register 0x18 Shadows */
   4152     for (i = 0; i <= 7; i++) {
   4153         WRITE_PHY_REG(unit, pc, 0x18, (i << 12) | 0x7);
   4154         READ_PHY_REG(unit, pc, 0x18, &tmp);
   4155         if ((tmp & ~7) == 0x0000) {
   4156             continue;
   4157         }
   4158         LOG_CLI((BSL_META_U(unit,
   4159                             "0x18[0x%x]=0x%04x\n"), i, tmp));
   4160     }
   4161 
   4162     /* Register 0x1c Shadows */
   4163     for (i = 0; i <= 0x1f; i++) {
   4164         WRITE_PHY_REG(unit, pc, 0x1c, i << 10);
   4165         READ_PHY_REG(unit, pc, 0x1c, &tmp);
   4166         if ((tmp & ~0x7c00) == 0x0000) {
   4167             continue;
   4168         }
   4169         LOG_CLI((BSL_META_U(unit,
   4170                             "0x1c[0x%x]=0x%04x\n"), i, tmp));
   4171     }
   4172 
   4173     /* Register 0x17/0x15 Shadows */
   4174     for (i = 0; i <= 0x13; i++) {
   4175         WRITE_PHY_REG(unit, pc, 0x17, 0xf00 | i);
   4176         READ_PHY_REG(unit, pc, 0x15, &tmp);
   4177         if (tmp  == 0x0000) {
   4178             continue;
   4179         }
   4180         LOG_CLI((BSL_META_U(unit,
   4181                             "0x17[0x%x]=0x%04x\n"), i, tmp));
   4182     }
   4183 }
   4184 
   4185 #endif /* BROADCOM_DEBUG */
   4186 
   4187 /*
   4188  * Variable:    phy_54616drv_ge
   4189  * Purpose:     PHY driver for 54616
   4190  */
   4191 
   4192 phy_driver_t phy_54616drv_ge = {
   4193     "54616/801x Gigabit PHY Driver",
   4194     phy_54616_init,
   4195     phy_fe_ge_reset,
   4196     phy_54616_link_get,
   4197     phy_54616_enable_set,
   4198     phy_54616_enable_get,
   4199     phy_54616_duplex_set,
   4200     phy_54616_duplex_get,
   4201     phy_54616_speed_set,
   4202     phy_54616_speed_get,
   4203     phy_54616_master_set,
   4204     phy_54616_master_get,
   4205     phy_54616_autoneg_set,
   4206     phy_54616_autoneg_get,
   4207     NULL, /* Local Advert set, deprecated */
   4208     NULL, /* Local Advert get, deprecated */
   4209     NULL, /* Remote Advert get, deprecated */
   4210     phy_54616_lb_set,
   4211     phy_54616_lb_get,
   4212     phy_54616_interface_set,
   4213     phy_54616_interface_get,
   4214     NULL,
   4215     NULL,                        /* Phy link up event */
   4216     NULL,                        /* Phy link down event */
   4217     phy_54616_mdix_set,
   4218     phy_54616_mdix_get,
   4219     phy_54616_mdix_status_get,
   4220     phy_54616_medium_config_set,
   4221     phy_54616_medium_config_get,
   4222     phy_54616_medium_status,
   4223     phy_54616_cable_diag,
   4224     NULL,                       /* phy_link_change */
   4225     phy_54616_control_set,       /* phy_control_set */ 
   4226     phy_54616_control_get,       /* phy_control_get */
   4227     phy_ge_reg_read,
   4228     phy_ge_reg_write,
   4229     phy_ge_reg_modify,
   4230     NULL,                        /* Phy event notify */ 
   4231     phy_54616_probe,          /* pd_probe  */
   4232     phy_54616_ability_advert_set,  /* pd_ability_advert_set */
   4233     phy_54616_ability_advert_get,  /* pd_ability_advert_get */
   4234     phy_54616_ability_remote_get,  /* pd_ability_remote_get */
   4235     phy_54616_ability_local_get,   /* pd_ability_local_get  */
   4236     NULL, /* pd_firmware_set */
   4237     phy_54618_timesync_config_set,
   4238     phy_54618_timesync_config_get,
   4239     phy_54618_timesync_control_set,
   4240     phy_54618_timesync_control_get
   4241 };
   4242 
   4243 #else /* INCLUDE_PHY_54616_ESW */
   4244 int _soc_phy_54616_not_empty;
   4245 #endif /* INCLUDE_PHY_54616 || INCLUDE_PHY_54618SE || INCLUDE_PHY_54618E */
   4246