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

phy54682.c (189309B)


      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:        phy54682.c
      8  * Purpose:     PHY driver for BCM54682
      9  *
     10  * Supported BCM54682 PHY device:
     11  *
     12  *      Device  Ports   Media                           MAC Interface
     13  *      54682   8       Copper/Serdes Combo             QSGMII
     14  *
     15  * Workarounds:
     16  *
     17  * References:
     18  * 54682-DS00-RDS.pdf        BCM54682 Data Sheet
     19  *
     20  * Notes:
     21  */ 
     22 
     23 #include <sal/types.h>
     24 #include <sal/core/spl.h>
     25 #include <shared/bsl.h>
     26 #include <soc/drv.h>
     27 #include <soc/debug.h>
     28 #include <soc/error.h>
     29 #include <soc/phyreg.h>
     30 
     31 #include <soc/phy.h>
     32 #include <soc/phy/phyctrl.h>
     33 #include <soc/phy/drv.h>
     34 
     35 #include "phydefs.h"      /* Must include before other phy related includes */
     36 
     37 #if defined(INCLUDE_PHY_54682)
     38 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     39 #include "phyident.h"
     40 #include "phyreg.h"
     41 #include "phyfege.h"
     42 #include "phy54682.h"
     43 
     44 #define AUTO_MDIX_WHEN_AN_DIS       0       /* Non-standard-compliant option */
     45 
     46 #define ECD_ENABLE 0
     47 
     48 #define ADVERT_ALL_COPPER \
     49         (SOC_PM_PAUSE | SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB)
     50 #define ADVERT_ALL_FIBER \
     51         (SOC_PM_PAUSE | SOC_PM_1000MB_FD)
     52 
     53 
     54 #define PHY_IS_BCM54682E(_pc)   (PHY_MODEL_CHECK((_pc), \
     55                                  PHY_BCM54682E_OUI, \
     56                                  PHY_BCM54682E_MODEL) \
     57                                  && (((_pc)->phy_rev & 0x08) == 0x0 ))
     58 
     59 #define PHY_IS_BCM54685E(_pc)   (PHY_MODEL_CHECK((_pc), \
     60                                  PHY_BCM54682E_OUI, \
     61                                  PHY_BCM54682E_MODEL) \
     62                                  && (((_pc)->phy_rev & 0x08) == 0x8 ))
     63 
     64 #define PHY_IS_BCM54682E_OR_BCM54685E(_pc)   (PHY_MODEL_CHECK((_pc), \
     65                                               PHY_BCM54682E_OUI, \
     66                                               PHY_BCM54682E_MODEL))
     67 
     68 #define PHY_IS_BCM54684E(_pc)   (PHY_MODEL_CHECK((_pc), \
     69                                  PHY_BCM54684E_OUI, \
     70                                  PHY_BCM54684E_MODEL))
     71 
     72 #define PHY_IS_BCM54685E_A0(_pc) (PHY_MODEL_CHECK((_pc), \
     73                                  PHY_BCM54682E_OUI, \
     74                                  PHY_BCM54682E_MODEL) \
     75                                  && ((_pc)->phy_rev == 0x8 ))
     76 
     77 #define PHY_IS_BCM54685E_A1(_pc) (PHY_MODEL_CHECK((_pc), \
     78                                  PHY_BCM54682E_OUI, \
     79                                  PHY_BCM54682E_MODEL) \
     80                                  && ((_pc)->phy_rev == 0x9 ))
     81 
     82 #define PHY_IS_BCM54685E_A0A1(_pc) (PHY_MODEL_CHECK((_pc), \
     83                                  PHY_BCM54682E_OUI, \
     84                                  PHY_BCM54682E_MODEL) \
     85                                  && (((_pc)->phy_rev & 0xe) == 0x8 ))
     86 
     87 #define PHY_IS_BCM54682E_OR_BCM54685E_A0A1(_pc) (PHY_MODEL_CHECK((_pc), \
     88                                  PHY_BCM54682E_OUI, \
     89                                  PHY_BCM54682E_MODEL) \
     90                                  && (((_pc)->phy_rev & 0x6) == 0x0 ))
     91 
     92 #define PHY_BCM54682_QSGMII_DEV_ADDR(_pc) \
     93             (PHY54682_FLAGS((_pc)) & PHY54682_PHYA_REV) ? (PHY54682_DEV_PHY_ID_BASE(_pc) + 1) : \
     94             (PHY54682_DEV_PHY_ID_BASE(_pc) + 8)
     95 
     96 #define SOC_IF_ERROR_BREAK(op, __rv__) \
     97         if (((__rv__) = (op)) < 0) {   \
     98             break;                     \
     99         }    
    100 
    101 STATIC int _phy_54682_qsgmii_aer[2] = {0x0, 0x4};
    102 
    103 STATIC int _phy_54682_tx_control_set(int unit, soc_port_t port,
    104                                  soc_phy_control_t type, uint32 value);
    105 STATIC int _phy_54682_tx_control_get(int unit, soc_port_t port,
    106                                  soc_phy_control_t type, uint32 *value);
    107 
    108 STATIC int _phy_54682_no_reset_setup(int unit, soc_port_t port);
    109 STATIC int _phy_54682_medium_change(int unit, soc_port_t port, int force_update);
    110 STATIC int phy_54682_duplex_set(int unit, soc_port_t port, int duplex);
    111 STATIC int phy_54682_speed_set(int unit, soc_port_t port, int speed);
    112 STATIC int phy_54682_master_set(int unit, soc_port_t port, int master);
    113 STATIC int phy_54682_autoneg_set(int unit, soc_port_t port, int autoneg);
    114 STATIC int phy_54682_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode);
    115 STATIC int phy_54682_speed_get(int unit, soc_port_t port, int *speed);
    116 STATIC int phy_54682_ability_local_get(int unit, soc_port_t port, 
    117                                        soc_port_ability_t *ability);
    118 STATIC int _phy_54682_ability_cu_local_get(int unit, soc_port_t port, 
    119                                        soc_port_ability_t *ability);
    120 STATIC int _phy_54682_ability_fiber_local_get(int unit, soc_port_t port, 
    121                                        soc_port_ability_t *ability);
    122 STATIC int phy_54682_ability_advert_set(int unit, soc_port_t port, 
    123                              soc_port_ability_t *ability);
    124 STATIC int phy_54682_control_set(int unit, soc_port_t port, 
    125                              soc_phy_control_t type, uint32 value);
    126 STATIC int phy_54682_control_get(int unit, soc_port_t port,
    127                              soc_phy_control_t type, uint32 *value);
    128 extern int
    129 phy_ecd_cable_diag_init(int unit, soc_port_t port);
    130 
    131 extern int
    132 phy_ecd_cable_diag(int unit, soc_port_t port,
    133             soc_port_cable_diag_t *status);
    134 
    135 /***********************************************************************
    136  *
    137  * HELPER FUNCTIONS
    138  */
    139 
    140 /*
    141  * Function:
    142  *      _phy_54682e_cl45_reg_read
    143  * Purpose:
    144  *      Read Clause 45 Register using Clause 22 register access
    145  * Parameters:
    146  *      unit      - StrataSwitch unit #.
    147  *      pc        - Phy control
    148  *      flags     - Flags
    149  *      dev_addr  - Clause 45 Device
    150  *      reg_addr  - Register Address to read
    151  *      val       - Value Read
    152  * Returns:
    153  *      SOC_E_XXX
    154  */
    155 
    156 STATIC int
    157 _phy_54682e_cl45_reg_read(int unit, phy_ctrl_t *pc, uint32 flags, 
    158                          uint8 dev_addr, uint16 reg_addr, uint16 *val)
    159 {
    160 
    161     /* Write Device Address to register 0x0D (Set Function field to Address)*/
    162     SOC_IF_ERROR_RETURN
    163         (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f)));
    164 
    165     /* Select the register by writing to register address to register 0x0E */
    166     SOC_IF_ERROR_RETURN
    167         (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr));
    168 
    169     /* Write Device Address to register 0x0D (Set Function field to Data)*/
    170     SOC_IF_ERROR_RETURN
    171         (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 
    172                            ((0x4000) | (dev_addr & 0x001f))));
    173 
    174     /* Read register 0x0E to get the value */
    175     SOC_IF_ERROR_RETURN
    176         (PHY54682_REG_READ(unit, pc, flags, 0x00, 0x0E, val));
    177 
    178     return SOC_E_NONE;
    179 }
    180 
    181 /*
    182  * Function:
    183  *      _phy_54682e_cl45_reg_write
    184  * Purpose:
    185  *      Write Clause 45 Register content using Clause 22 register access
    186  * Parameters:
    187  *      unit      - StrataSwitch unit #.
    188  *      pc        - Phy control
    189  *      flags     - Flags
    190  *      dev_addr  - Clause 45 Device
    191  *      reg_addr  - Register Address to read
    192  *      val       - Value to be written
    193  * Returns:
    194  *      SOC_E_XXX
    195  */
    196 
    197 STATIC int
    198 _phy_54682e_cl45_reg_write(int unit, phy_ctrl_t *pc, uint32 flags, 
    199                          uint8 dev_addr, uint16 reg_addr, uint16 val)
    200 {
    201 
    202     /* Write Device Address to register 0x0D (Set Function field to Address)*/
    203     SOC_IF_ERROR_RETURN
    204         (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, (dev_addr & 0x001f)));
    205 
    206     /* Select the register by writing to register address to register 0x0E */
    207     SOC_IF_ERROR_RETURN
    208         (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0E, reg_addr));
    209 
    210     /* Write Device Address to register 0x0D (Set Function field to Data)*/
    211     SOC_IF_ERROR_RETURN
    212         (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0D, 
    213                            ((0x4000) | (dev_addr & 0x001f))));
    214 
    215     /* Write register 0x0E to write the value */
    216     SOC_IF_ERROR_RETURN
    217         (PHY54682_REG_WRITE(unit, pc, flags, 0x00, 0x0E, val));
    218 
    219     return SOC_E_NONE;
    220 }
    221 
    222 /*
    223  * Function:
    224  *      _phy_54682e_cl45_reg_modify
    225  * Purpose:
    226  *      Modify Clause 45 Register contents using Clause 22 register access
    227  * Parameters:
    228  *      unit      - StrataSwitch unit #.
    229  *      pc        - Phy control
    230  *      flags     - Flags
    231  *      reg_bank  - Register bank
    232  *      dev_addr  - Clause 45 Device
    233  *      reg_addr  - Register Address to read
    234  *      val       - Value 
    235  *      mask      - Mask for modifying the contents of the register
    236  * Returns:
    237  *      SOC_E_XXX
    238  */
    239 
    240 STATIC int
    241 _phy_54682e_cl45_reg_modify(int unit, phy_ctrl_t *pc, uint32 flags, 
    242                           uint8 dev_addr, uint16 reg_addr, uint16 val, 
    243                           uint16 mask)
    244 {
    245 
    246     uint16 value = 0;
    247 
    248     SOC_IF_ERROR_RETURN
    249         (PHY54682E_CL45_REG_READ(unit, pc, flags, dev_addr, reg_addr, &value));
    250 
    251     value = (val & mask) | (value & ~mask);
    252 
    253     SOC_IF_ERROR_RETURN
    254         (PHY54682E_CL45_REG_WRITE(unit, pc, flags, dev_addr, reg_addr, value));
    255 
    256     return SOC_E_NONE;
    257 }
    258 
    259 /*
    260  * Function:
    261  *      _phy_54682e_blk_top_lvl_reg_read
    262  * Purpose:
    263  *      New mechanism to Read Top Level Registers for EEE and 1588.
    264  * Parameters:
    265  *      unit       - StrataSwitch unit #.
    266  *      pc         - Phy control
    267  *      flags      - Flags
    268  *      reg_offset - Register Address to read
    269  *      val        - Value Read
    270  * Returns:
    271  *      SOC_E_XXX
    272  */
    273 
    274 STATIC int
    275 _phy_54682e_blk_top_lvl_reg_read(int unit, phy_ctrl_t *pc, uint32 flags, 
    276                          uint16 reg_offset, uint16 *val)
    277 {
    278     /* Write register 0x17 with the top level reg offset to read (handled in PHY54682_REG_READ) */
    279     /* Read register 0x15 to get the value */
    280     SOC_IF_ERROR_RETURN
    281         (PHY54682_REG_READ(unit, pc, flags, (0x0D00|(reg_offset & 0xff)), 0x15, val));
    282 
    283     return SOC_E_NONE;
    284 }
    285 
    286 /*
    287  * Function:
    288  *      _phy_54682e_blk_top_lvl_reg_write
    289  * Purpose:
    290  *      New mechanism to Write Top Level Registers for EEE and 1588
    291  * Parameters:
    292  *      unit      - StrataSwitch unit #.
    293  *      pc        - Phy control
    294  *      flags     - Flags
    295  *      reg_offset  - Register Address to read
    296  *      val       - Value to be written
    297  * Returns:
    298  *      SOC_E_XXX
    299  */
    300 
    301 STATIC int
    302 _phy_54682e_blk_top_lvl_reg_write(int unit, phy_ctrl_t *pc, uint32 flags, 
    303                                   uint16 reg_offset, uint16 val)
    304 {
    305     /* Write register 0x17 with the top level reg offset to write (handled in PHY54682_REG_WRITE) */
    306     /* Write register 0x15 the value to write to the top level register offset */
    307     SOC_IF_ERROR_RETURN
    308         (PHY54682_REG_WRITE(unit, pc, flags, (0x0D00|(reg_offset & 0xff)), 0x15, val));
    309 
    310     return SOC_E_NONE;
    311 }
    312 
    313 /*
    314  * Function:
    315  *      _phy_54682e_blk_top_lvl_reg_modify
    316  * Purpose:
    317  *      Modify Clause 45 Register contents using Clause 22 register access
    318  * Parameters:
    319  *      unit      - StrataSwitch unit #.
    320  *      pc        - Phy control
    321  *      flags     - Flags
    322  *      reg_bank  - Register bank
    323  *      dev_addr  - Clause 45 Device
    324  *      reg_addr  - Register Address to read
    325  *      val       - Value 
    326  *      mask      - Mask for modifying the contents of the register
    327  * Returns:
    328  *      SOC_E_XXX
    329  */
    330 
    331 STATIC int
    332 _phy_54682e_blk_top_lvl_reg_modify(int unit, phy_ctrl_t *pc, uint32 flags,
    333                           uint16 reg_offset, uint16 val, uint16 mask)
    334 {
    335 
    336     uint16 value = 0;
    337 
    338     /* Write register 0x17 with the top level reg offset to read */
    339     SOC_IF_ERROR_RETURN
    340         (_phy_54682e_blk_top_lvl_reg_read(unit, pc, flags, 
    341                                           reg_offset, &value));
    342 
    343     value = (val & mask) | (value & ~mask);
    344 
    345     /* Write register 0x17 with the top level reg offset to read */
    346     SOC_IF_ERROR_RETURN
    347         (_phy_54682e_blk_top_lvl_reg_write(unit, pc, flags, 
    348                                            reg_offset, value));
    349     return SOC_E_NONE;
    350 }
    351 
    352 /*
    353  * Function:
    354  *      phy_54682_toplvl_reg_read
    355  * Purpose:
    356  *      Read a top level register from a supporting chip
    357  * Parameters:
    358  *      unit - SOC Unit #.
    359  *      port - Port number.
    360  *      flags - 
    361  *      reg_offset  - Offset to the reg
    362  *      data  - Pointer to data returned
    363  * Returns:
    364  *      SOC_E_XXX
    365  */
    366 int
    367 phy_54682_toplvl_reg_read(int unit, soc_port_t port, int flags, uint8 reg_offset, uint16 *data)
    368 {
    369     phy_ctrl_t    *pc;
    370     uint16 reg_data, status;
    371     int         rv = SOC_E_NONE;
    372 
    373     LOG_VERBOSE(BSL_LS_SOC_PHY,
    374                 (BSL_META_U(unit,
    375                             "entered phy_54682_toplvl_reg_read: "
    376                             "unit %d, port %d, flags %x reg_offset %u\n"), 
    377                  unit, port, flags, reg_offset));
    378     
    379     pc = EXT_PHY_SW_STATE(unit, port);
    380 
    381     /* Write Reg address to Port 5's (offset=4) register 0x1C, shadow 0x0B */
    382     /* Status READ from Port 3's (offset=2) register 0x15 */
    383 
    384     /* Write Reg offset to Port 5's register 0x1C, shadow 0x0B */
    385     reg_data = (0xAC00 | reg_offset);
    386     INT_MCU_LOCK(unit);
    387     pc->phy_id =  PHY54682_SLICE_ADDR(pc, 4);
    388     rv = pc->write(unit, pc->phy_id, 0x1c, reg_data);
    389     if (SOC_FAILURE(rv)) {
    390         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    391         INT_MCU_UNLOCK(unit);
    392         return rv;
    393     }
    394 
    395     pc->phy_id =  PHY54682_SLICE_ADDR(pc, 2);
    396     /* Read data from Top level MII Status register(0x15h) */
    397     rv = pc->write(unit, pc->phy_id, 0x17, 0x8F0B);
    398     if (SOC_FAILURE(rv)) {
    399         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    400         INT_MCU_UNLOCK(unit);
    401         return rv;
    402     }
    403     rv = pc->read(unit, pc->phy_id, 0x15, &status);
    404     INT_MCU_UNLOCK(unit);
    405     if (SOC_FAILURE(rv)) {
    406         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    407         return rv;
    408     }
    409 
    410     *data = (status & 0xff);
    411 
    412     pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    413 
    414     return SOC_E_NONE;
    415 }
    416 
    417 /*
    418  * Function:
    419  *      phy_54682_toplvl_reg_write
    420  * Purpose:
    421  *      Write to a top level register from a supporting chip
    422  * Parameters:
    423  *      unit - SOC Unit #.
    424  *      port - Port number.
    425  *      flags - 
    426  *      reg_offset  - Offset to the reg
    427  *      data  - Data to be written
    428  * Returns:
    429  *      SOC_E_XXX
    430  */
    431 int
    432 phy_54682_toplvl_reg_write(int unit, soc_port_t port, int flags, uint8 reg_offset, uint16 data)
    433 {
    434     phy_ctrl_t *pc;
    435     uint16 reg_data;
    436 #ifdef BROADCOM_DEBUG
    437     uint16 status;
    438 #endif
    439     int         rv = SOC_E_NONE;
    440     
    441     LOG_VERBOSE(BSL_LS_SOC_PHY,
    442                 (BSL_META_U(unit,
    443                             "entered phy_54682_toplvl_reg_write: "
    444                             "unit %d, port %d, flags %x reg_offset %u, data %u\n"), 
    445                  unit, port, flags, reg_offset, data));
    446 
    447     pc       = EXT_PHY_SW_STATE(unit, port);
    448 
    449     /* Write Reg address to Port 5's register 0x1C, shadow 0x0B */
    450     /* Write data to Port 6's register 0x1C, shadow 0x0c */
    451     /* Status READ from Port 3's register 0x15 */
    452 
    453     /* Write Data to port6 (offset = 5), register 0x1C, shadow 0x0c */
    454     INT_MCU_LOCK(unit);
    455     pc->phy_id =  PHY54682_SLICE_ADDR(pc, 5);
    456     reg_data = (0xB000 | (data & 0xff));
    457     rv = pc->write(unit, pc->phy_id, 0x1c, reg_data);
    458     if (SOC_FAILURE(rv)) {
    459         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    460         INT_MCU_UNLOCK(unit);
    461         return rv;
    462     }
    463 
    464     pc->phy_id =  PHY54682_SLICE_ADDR(pc, 4);
    465     /* Write Reg address to Port 5's (offset = 4) register 0x1C, shadow 0x0B */
    466     /* Enable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 1 */
    467     reg_data = (0xAC80 | reg_offset);
    468     rv = pc->write(unit, pc->phy_id, 0x1c, reg_data);
    469     if (SOC_FAILURE(rv)) {
    470         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    471         INT_MCU_UNLOCK(unit);
    472         return rv;
    473     }
    474 
    475     /* Disable Write ( Port 5's register 0x1C, shadow 0x0B) Bit 7 = 0 */
    476     reg_data = (0xAC00 | reg_offset);
    477     rv = pc->write(unit, pc->phy_id, 0x1c, reg_data);
    478     if (SOC_FAILURE(rv)) {
    479         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    480         INT_MCU_UNLOCK(unit);
    481         return rv;
    482     }
    483 
    484 #ifdef BROADCOM_DEBUG
    485     pc->phy_id =  PHY54682_SLICE_ADDR(pc, 2);
    486     /* Read data from Top level MII Status register(0x15h) */
    487     rv = pc->write(unit, pc->phy_id, 0x17, 0x8F0B);
    488     if (SOC_FAILURE(rv)) {
    489         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    490         INT_MCU_UNLOCK(unit);
    491         return rv;
    492     }
    493     rv = pc->read(unit, pc->phy_id, 0x15, &status);
    494 
    495     if (SOC_FAILURE(rv)) {
    496         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    497         INT_MCU_UNLOCK(unit);
    498         return rv;
    499     }
    500 #endif
    501 
    502     pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
    503     INT_MCU_UNLOCK(unit);
    504 
    505     return SOC_E_NONE;
    506 }
    507 
    508 /*
    509  * Function:
    510  *      _phy_54682_medium_check
    511  * Purpose:
    512  *      Determine if chip should operate in copper or fiber mode.
    513  * Parameters:
    514  *      unit - StrataSwitch unit #.
    515  *      port - StrataSwitch port #.
    516  *      medium - (OUT) SOC_PORT_MEDIUM_XXX
    517  * Returns:
    518  *      SOC_E_XXX
    519  */
    520 STATIC int
    521 _phy_54682_medium_check(int unit, soc_port_t port, int *medium)
    522 {
    523     phy_ctrl_t    *pc = EXT_PHY_SW_STATE(unit, port);
    524     uint16         tmp = 0xffff;
    525 
    526     *medium = SOC_PORT_MEDIUM_COPPER;
    527 
    528     if (pc->automedium) {
    529         /* Read Mode Register (0x1c shadow 11111) */
    530         SOC_IF_ERROR_RETURN
    531             (READ_PHY54682_MODE_CTRLr(unit, pc, &tmp));
    532 
    533         if (pc->fiber.preferred) {
    534             /* 0x10 Fiber Signal Detect
    535              * 0x20 Copper Energy Detect
    536              */
    537             if ((tmp & 0x30) == 0x20) {
    538                 /* Only copper is link up */
    539                 *medium = SOC_PORT_MEDIUM_COPPER;
    540             } else {
    541                 *medium = SOC_PORT_MEDIUM_FIBER;
    542             }
    543         } else {
    544             if ((tmp & 0x30) == 0x10) {
    545                 /* Only fiber is link up */
    546                 *medium = SOC_PORT_MEDIUM_FIBER;
    547             } else {
    548                 *medium = SOC_PORT_MEDIUM_COPPER;
    549             }
    550         }
    551     } else {
    552         *medium = pc->fiber.preferred ? SOC_PORT_MEDIUM_FIBER:
    553                   SOC_PORT_MEDIUM_COPPER;
    554     }
    555    
    556     LOG_VERBOSE(BSL_LS_SOC_PHY,
    557                 (BSL_META_U(unit,
    558                             "_phy_54682_medium_check: "
    559                             "u=%d p=%d fiber_pref=%d 0x1c(11111)=%04x fiber=%d\n"),
    560                  unit, port, pc->fiber.preferred, tmp, 
    561                  (*medium == SOC_PORT_MEDIUM_FIBER) ? 1 : 0));
    562 
    563     return SOC_E_NONE;
    564 }
    565 
    566 /*
    567  * Function:
    568  *      phy_54682_medium_status
    569  * Purpose:
    570  *      Indicate the current active medium
    571  * Parameters:
    572  *      unit - StrataSwitch unit #.
    573  *      port - StrataSwitch port #.
    574  *      medium - (OUT) One of:
    575  *              SOC_PORT_MEDIUM_COPPER
    576  *              SOC_PORT_MEDIUM_FIBER
    577  * Returns:
    578  *      SOC_E_NONE
    579  */
    580 
    581 STATIC int
    582 phy_54682_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium)
    583 {
    584     if (PHY_COPPER_MODE(unit, port)) {
    585         *medium = SOC_PORT_MEDIUM_COPPER;
    586     } else {
    587         *medium = SOC_PORT_MEDIUM_FIBER;
    588     }
    589     return SOC_E_NONE;
    590 }
    591 
    592 /*
    593  * Function:
    594  *      _phy_54682_medium_config_update
    595  * Purpose:
    596  *      Update the PHY with config parameters
    597  * Parameters:
    598  *      unit - StrataSwitch unit #.
    599  *      port - StrataSwitch port #.
    600  *      cfg - Config structure.
    601  * Returns:
    602  *      SOC_E_XXX
    603  */
    604 
    605 STATIC int
    606 _phy_54682_medium_config_update(int unit, soc_port_t port,
    607                                 soc_phy_config_t *cfg)
    608 {
    609     SOC_IF_ERROR_RETURN
    610         (phy_54682_speed_set(unit, port, cfg->force_speed));
    611     SOC_IF_ERROR_RETURN
    612         (phy_54682_duplex_set(unit, port, cfg->force_duplex));
    613     SOC_IF_ERROR_RETURN
    614         (phy_54682_master_set(unit, port, cfg->master));
    615     SOC_IF_ERROR_RETURN
    616         (phy_54682_ability_advert_set(unit, port, &cfg->advert_ability));
    617     SOC_IF_ERROR_RETURN
    618         (phy_54682_autoneg_set(unit, port, cfg->autoneg_enable));
    619     SOC_IF_ERROR_RETURN
    620         (phy_54682_mdix_set(unit, port, cfg->mdix));
    621 
    622     return SOC_E_NONE;
    623 }
    624 
    625 /***********************************************************************
    626  *
    627  * PHY54682 DRIVER ROUTINES
    628  */
    629 
    630 /*
    631  * Function:
    632  *      phy_54682_medium_config_set
    633  * Purpose:
    634  *      Set the operating parameters that are automatically selected
    635  *      when medium switches type.
    636  * Parameters:
    637  *      unit - StrataSwitch unit #
    638  *      port - Port number
    639  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    640  *      cfg - Operating parameters
    641  * Returns:
    642  *      SOC_E_XXX
    643  */
    644 
    645 STATIC int
    646 phy_54682_medium_config_set(int unit, soc_port_t port, 
    647                            soc_port_medium_t  medium,
    648                            soc_phy_config_t  *cfg)
    649 {
    650     phy_ctrl_t    *pc;
    651     soc_phy_config_t *active_medium;  /* Currently active medium */
    652     soc_phy_config_t *change_medium;  /* Requested medium */
    653     soc_phy_config_t *other_medium;   /* The other medium */
    654     int               medium_update;
    655     soc_port_mode_t   advert_mask;
    656 
    657     if (NULL == cfg) {
    658         return SOC_E_PARAM;
    659     }
    660 
    661     pc            = EXT_PHY_SW_STATE(unit, port);
    662     medium_update = FALSE;
    663 
    664    switch (medium) {
    665     case SOC_PORT_MEDIUM_COPPER:
    666         if (!pc->automedium) {
    667             if (!PHY_COPPER_MODE(unit, port)) {
    668                 return SOC_E_UNAVAIL;
    669             }
    670             /* check if device is fiber capable before switching */
    671             if (cfg->preferred == 0) {
    672                 uint16 data;
    673 
    674                 SOC_IF_ERROR_RETURN
    675                     (READ_PHY54682_MODE_CTRLr(unit, pc, &data));
    676  
    677                 /* return if not fiber capable*/
    678                 if (!(data & 0x8)) {
    679                     return SOC_E_UNAVAIL;
    680                 }
    681             }
    682         }
    683 
    684         change_medium  = &pc->copper;
    685         other_medium   = &pc->fiber;
    686         advert_mask    = ADVERT_ALL_COPPER;
    687         break;
    688     case SOC_PORT_MEDIUM_FIBER:
    689         if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) {
    690             return SOC_E_UNAVAIL;
    691         }
    692         change_medium  = &pc->fiber;
    693         other_medium   = &pc->copper;
    694         advert_mask    = ADVERT_ALL_FIBER;
    695         break;
    696     default:
    697         return SOC_E_PARAM;
    698     }
    699 
    700     /*
    701      * Changes take effect immediately if the target medium is active or
    702      * the preferred medium changes.
    703      */
    704     if (change_medium->enable != cfg->enable) {
    705         medium_update = TRUE;
    706     }
    707     if (change_medium->preferred != cfg->preferred) {
    708         /* Make sure that only one medium is preferred */
    709         other_medium->preferred = !cfg->preferred;
    710         medium_update = TRUE;
    711     }
    712 
    713     sal_memcpy(change_medium, cfg, sizeof(*change_medium));
    714     change_medium->autoneg_advert &= advert_mask;
    715 
    716     if (medium_update) {
    717         /* The new configuration may cause medium change. Check
    718          * and update medium.
    719          */
    720         SOC_IF_ERROR_RETURN
    721             (_phy_54682_medium_change(unit, port, TRUE));
    722     } else {
    723         active_medium = (PHY_COPPER_MODE(unit, port)) ?  
    724                             &pc->copper : &pc->fiber;
    725         if (active_medium == change_medium) {
    726             /* If the medium to update is active, update the configuration */
    727             SOC_IF_ERROR_RETURN
    728                 (_phy_54682_medium_config_update(unit, port, change_medium));
    729         }
    730     }
    731     return SOC_E_NONE;
    732 }
    733 
    734 /*
    735  * Function:
    736  *      phy_54682_medium_config_get
    737  * Purpose:
    738  *      Get the operating parameters that are automatically selected
    739  *      when medium switches type.
    740  * Parameters:
    741  *      unit - StrataSwitch unit #
    742  *      port - Port number
    743  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    744  *      cfg - (OUT) Operating parameters
    745  * Returns:
    746  *      SOC_E_XXX
    747  */
    748 
    749 STATIC int
    750 phy_54682_medium_config_get(int unit, soc_port_t port, 
    751                            soc_port_medium_t medium,
    752                            soc_phy_config_t *cfg)
    753 {
    754     int            rv;
    755     phy_ctrl_t    *pc;
    756 
    757     pc = EXT_PHY_SW_STATE(unit, port);
    758     rv = SOC_E_NONE;
    759 
    760     switch (medium) {
    761     case SOC_PORT_MEDIUM_COPPER:
    762         if (pc->automedium || PHY_COPPER_MODE(unit, port)) {
    763             sal_memcpy(cfg, &pc->copper, sizeof (*cfg));
    764         } else {
    765             rv = SOC_E_UNAVAIL;
    766         }
    767         break;
    768     case SOC_PORT_MEDIUM_FIBER:
    769         if (pc->automedium || PHY_FIBER_MODE(unit, port)) {
    770             sal_memcpy(cfg, &pc->fiber, sizeof (*cfg));
    771         } else {
    772             rv = SOC_E_UNAVAIL;
    773         }
    774         break;
    775     default:
    776         rv = SOC_E_PARAM;
    777         break;
    778     }
    779 
    780     return rv;
    781 }
    782 
    783 #define FIBER_POWER_UP          1
    784 #define FIBER_POWER_DOWN        0          
    785 
    786 STATIC int
    787 _phy_54685_fiber_power_control(int unit, phy_ctrl_t *pc, int power_up)
    788 {
    789     if ( PHY54682_DEV_PHY_SLICE_IS_LAST2(pc) ) {
    790         /* WAR for the last 2 ports in the chip */
    791         if ( power_up ) {
    792             /*  Enable TX.  Misc 1000-X Control Reg. (1C shadow 17h) bit[6]=0 */
    793             SOC_IF_ERROR_RETURN(
    794                 MODIFY_PHY54682_MISC_1000X_CONTROLr(unit, pc,
    795                                     PHY_54682_MISC_1000X_SERDES_TX_ENABLE,
    796                                     PHY_54682_MISC_1000X_SERDES_TX_MASK) );
    797             /*  Reset PHY.  1000-x MII Control  Reg. (1000X Reg. 00h) bit[15] */
    798             SOC_IF_ERROR_RETURN(
    799                 MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc,
    800                                     MII_CTRL_RESET,
    801                                     MII_CTRL_RESET | MII_CTRL_PD) );
    802         } else {   /* power down */
    803             /*  Invert SD.  Auto-Detect Medium  Reg. (1C shadow 1eh) bit[8]=1 */
    804             SOC_IF_ERROR_RETURN
    805                 (MODIFY_PHY54682_AUTO_DETECT_MEDIUMr(unit, pc,
    806                                     PHY_54682_AUTO_DETECT_MEDIUM_INVERT_SD,
    807                                     PHY_54682_AUTO_DETECT_MEDIUM_INVERT_SD) );
    808             /* Disable TX.  Misc 1000-X Control Reg. (1C shadow 17h) bit[6]=1 */
    809             SOC_IF_ERROR_RETURN(
    810                 MODIFY_PHY54682_MISC_1000X_CONTROLr(unit, pc,
    811                                     PHY_54682_MISC_1000X_SERDES_TX_DISABLE,
    812                                     PHY_54682_MISC_1000X_SERDES_TX_MASK) );
    813         }
    814 
    815     } else {
    816         /* normal power up/down sequence for first 6 ports */
    817         SOC_IF_ERROR_RETURN(
    818             MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc,
    819                                 (power_up) ? 0 : MII_CTRL_PD, MII_CTRL_PD) );
    820     }
    821     return SOC_E_NONE;
    822 }
    823 
    824 /*
    825  * Function:
    826  *      _phy_54682_reset_setup
    827  * Purpose:
    828  *      Function to reset the PHY and set up initial operating registers.
    829  * Parameters:
    830  *      unit - StrataSwitch unit #.
    831  *      port - StrataSwitch port #.
    832  * Returns:
    833  *      SOC_E_XXX
    834  * Notes:
    835  *      Configures for copper/fiber according to the current
    836  *      setting of PHY_FLAGS_FIBER.
    837  */
    838 
    839 STATIC int
    840 _phy_54682_reset_setup(int unit, soc_port_t port)
    841 {
    842     phy_ctrl_t    *pc;
    843     soc_port_t     primary_port;
    844     int            index;
    845 
    846     pc = EXT_PHY_SW_STATE(unit, port);
    847 
    848     /* Reset the PHY with previously registered callback function. */
    849     SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port));
    850 
    851     if ( soc_phy_primary_and_offset_get(unit, port, &primary_port, &index)
    852                                        == SOC_E_NONE ) {
    853         /* determine the order of logical ports on a PHY chip */
    854         if ( index & 0x80 ) {
    855             PHY54682_FLAGS(pc) |= ( PHY54682_PHYA_REV);    /* reverse order */
    856         } else {
    857             PHY54682_FLAGS(pc) &= (~PHY54682_PHYA_REV);    /* normal  order */
    858         }
    859     } else {
    860         /* config variable 'phy_port_primary_and_offset' not specified  *\
    861         |* Assign default values in a 4-alignment basis :               *|
    862         |*    e.g.         port =  2 3 4 5 6 7 8 9                      *|
    863         |*                index =  0 1 2 3 0 1 2 3                      *|
    864         \*         primary_port =  2 2 2 2 6 6 6 6                      */
    865         index        = pc->phy_id & ( PHY54682_DEV_PHY_SLICE_MASK);
    866         primary_port = ((port - index) <= 0) ?  0 :  (port - index);
    867         PHY54682_FLAGS(pc) &= (~PHY54682_PHYA_REV);        /* normal  order */
    868         LOG_WARN(BSL_LS_SOC_PHY,
    869                  (BSL_META_U(unit,
    870                              "Config property 'phy_port_primary_and_offset' "
    871                              "not set for unit %d, port %d.  "
    872                              "Default to slice=0x%x, base=0x%x\n"),
    873                              unit, port, index, primary_port));
    874     }
    875     pc->lane_num = index;
    876 
    877     /* keep the original MDIO address.  Set slice ID & base PHY address */
    878     /*   Do not change the order to the following four lines */
    879     index &= ~0x80;    /* clear reverse bit (PHYA_REV) */
    880     PHY54682_DEV_PHY_ID_ORIG(pc) = pc->phy_id;
    881     PHY54682_DEV_PHY_SLICE(pc)   = index;
    882     PHY54682_DEV_SET_BASE_ADDR(pc);   /* phy address of port 0 of this chip */
    883 
    884     SOC_IF_ERROR_RETURN
    885         (phy_54682_control_set( unit, port, SOC_PHY_CONTROL_PORT_PRIMARY,
    886                                             primary_port));
    887     SOC_IF_ERROR_RETURN
    888         (phy_54682_control_set( unit, port, SOC_PHY_CONTROL_PORT_OFFSET,
    889                                             index ));
    890     /* Disable super-isolate */
    891     SOC_IF_ERROR_RETURN
    892         (MODIFY_PHY54682_MII_POWER_CTRLr(unit, pc, 0x0, 1U<<5));
    893 
    894     /* BCM54682E is EEE capable */
    895     if ( PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc) ) {
    896         SOC_IF_ERROR_RETURN
    897            (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7, 0x0000, 0x0003));
    898         PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE);
    899 
    900         SOC_IF_ERROR_RETURN
    901             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0F7F,0x15, 0x0, 0x7)); /* exp 7f */
    902     }
    903 
    904     if ( ECD_ENABLE &&
    905          ( ((PHY_IS_BCM54682E_OR_BCM54685E(pc)) || (PHY_IS_BCM54684E(pc))) &&
    906            ((pc->phy_rev & 0x7) > 0x2) )   ) {
    907         SOC_IF_ERROR_RETURN(
    908             phy_ecd_cable_diag_init(unit, port));
    909     }
    910 
    911     SOC_IF_ERROR_RETURN(_phy_54682_no_reset_setup(unit, port));
    912     return SOC_E_NONE;
    913 }
    914 
    915 STATIC int
    916 _phy_54682_no_reset_setup(int unit, soc_port_t port)
    917 {
    918     phy_ctrl_t    *pc;
    919     uint16         data, mask;
    920 
    921     LOG_INFO(BSL_LS_SOC_PHY,
    922              (BSL_META_U(unit,
    923                          "_phy_54682_reset_setup: u=%d p=%d medium=%s\n"),
    924                          unit, port,
    925               PHY_COPPER_MODE(unit, port) ? "COPPER" : "FIBER"));
    926 
    927     pc      = EXT_PHY_SW_STATE(unit, port);
    928 
    929     /*
    930      * Workaround for BCM54682 B0 chip
    931      * (not necessary for B1 and C0 chip)
    932      * Description: BCM54682 defaults into the SGMII/QSGMII-to-copper split 
    933      *    mode after reset. The BCM54682 device mode should default into the 
    934      *    QSMII-to-Copper mode after reset.
    935      */
    936     if(PHY_REVISION_CHECK(pc, PHY_BCM54682E_MODEL, PHY_BCM54682E_OUI, 0x0)) {
    937         SOC_IF_ERROR_RETURN
    938             (MODIFY_PHY54682_MODE_CTRLr(unit, pc, 0x0000, 0x0006));
    939     }
    940 
    941     /* SGMII interface to MAC */
    942     
    943     /* soc_phy_reset has reset the phy, power down the unstrapped interface. *\
    944     \* Make sure enabled interfaces are powered up.                          */
    945     SOC_IF_ERROR_RETURN(
    946         _phy_54685_fiber_power_control(unit, pc, FIBER_POWER_UP) );
    947 
    948     /* 1000Base-X FullDuplex will be clear after the phy been reset in 54682 */
    949     data = MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_RAN | MII_CTRL_AE;
    950     
    951     SOC_IF_ERROR_RETURN
    952         (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc, data));
    953    
    954     /* copper regs */
    955     if ( !pc->copper.enable || (!pc->automedium && pc->fiber.preferred) ) {
    956         /* Copper interface is not used. Powered down. */
    957         SOC_IF_ERROR_RETURN
    958             (MODIFY_PHY54682_MII_CTRLr(unit, pc, MII_CTRL_PD, MII_CTRL_PD));
    959     } else {
    960         SOC_IF_ERROR_RETURN
    961             (MODIFY_PHY54682_MII_CTRLr(unit, pc, 0, MII_CTRL_PD));
    962         SOC_IF_ERROR_RETURN
    963             (WRITE_PHY54682_MII_GB_CTRLr(unit, pc,  
    964                             MII_GB_CTRL_ADV_1000FD | MII_GB_CTRL_PT));
    965         SOC_IF_ERROR_RETURN
    966             (WRITE_PHY54682_MII_CTRLr(unit, pc, 
    967                 MII_CTRL_FD | MII_CTRL_SS_10 | 
    968                 MII_CTRL_SS_100 | MII_CTRL_AE));
    969     }
    970           
    971     /* Adjust timing and enable link speed led mode */
    972     SOC_IF_ERROR_RETURN
    973         (MODIFY_PHY54682_SPARE_CTRLr(unit, pc, 0x0006, 0x0006));
    974 
    975     /* Power down SerDes */
    976     SOC_IF_ERROR_RETURN(
    977         _phy_54685_fiber_power_control(unit, pc, FIBER_POWER_DOWN) ) ;
    978 
    979     if (pc->fiber.enable && (pc->automedium || pc->fiber.preferred)) {
    980         /* remove power down of SerDes */
    981         SOC_IF_ERROR_RETURN(
    982             _phy_54685_fiber_power_control(unit, pc, FIBER_POWER_UP) );
    983 
    984         /* set the advertisement of serdes */
    985         /* Disable half-duplex, full-duplex capable */
    986         SOC_IF_ERROR_RETURN
    987             (MODIFY_PHY54682_1000X_MII_ANAr(unit, pc, (1 << 5), 
    988                                                 (1 << 5) | (1 << 6)));
    989         /* Enable auto-detection between SGMII-slave and 1000BASE-X */
    990         SOC_IF_ERROR_RETURN
    991             (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 1, 1));
    992 
    993         /* Restart SerDes autonegotiation */
    994         SOC_IF_ERROR_RETURN
    995             (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc,
    996                                 MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE));
    997         
    998         switch (pc->fiber_detect) {
    999             case  2:         /* LED 2 */
   1000             case -2:
   1001             case  4:         /* LED 4 : kept for backward compatibility */
   1002             case -4:
   1003             case  10:        /* EN_10B for signal detect */
   1004             case -10:
   1005             case 0:         /* default */
   1006                 /* GPIO Control/Status Register (0x1c shadow 01111) */
   1007                 /* Change LED2 pin into an input */
   1008                 SOC_IF_ERROR_RETURN
   1009                     (MODIFY_PHY54682_LED_GPIO_CTRLr(unit, pc, 0x08, 0x08));
   1010                 break;
   1011             case  1:         /* PECL , no such pin in 54682 data sheet */
   1012             case -1:
   1013             default:
   1014                 return SOC_E_CONFIG;
   1015         }
   1016         SOC_IF_ERROR_RETURN
   1017             (MODIFY_PHY54682_MODE_CTRLr(unit, pc, 0x0002, 0x0006));        
   1018     }
   1019 
   1020     /* In BCM546682 the SD pin is internally tied. Ignore SD pin for
   1021        proper operation. 
   1022      */
   1023     SOC_IF_ERROR_RETURN
   1024         (MODIFY_PHY54682_MISC_1000X_CONTROLr(unit, pc, 0x0000, 0x0020));
   1025 
   1026     /* Configure Auto-detect Medium (0x1c shadow 11110) */
   1027     mask = 0x33f;               /* Auto-detect bit mask */
   1028     data = 0;
   1029 
   1030     /* In BCM546682 the SD pin is internally tied. For proper operation
   1031        SD_INV and QUALIFY_SD_WITH_SYNC should be set.
   1032      */
   1033     data = (1 << 8) | (1 << 5);
   1034 
   1035     if (pc->automedium) {
   1036         data |= 1 << 0;    /* Enable auto-detect medium */
   1037     }
   1038 
   1039     /* When no link partner exists, fiber should be default medium */
   1040     /* When both link partners exipc, fiber should be prefered medium
   1041      * for the following reasons.
   1042      * 1. Most fiber module generates signal detect when the fiber cable is
   1043      *    plugged in regardless of any activity even if the link partner is
   1044      *    powered down.
   1045      * 2. Fiber mode consume much lesser power than copper mode.
   1046      */
   1047     if (pc->fiber.preferred) {
   1048         data |= 1 << 1;    /* Fiber selected when both media are active */
   1049         data |= 1 << 2;    /* Fiber selected when no medium is active */
   1050     }
   1051 
   1052     SOC_IF_ERROR_RETURN
   1053         (MODIFY_PHY54682_AUTO_DETECT_MEDIUMr(unit, pc, data, mask));
   1054 
   1055 #if AUTO_MDIX_WHEN_AN_DIS
   1056     /* Enable Auto-MDIX When autoneg disabled */
   1057     SOC_IF_ERROR_RETURN
   1058         (MODIFY_PHY54682_MII_MISC_CTRLr(unit, pc, 0x200, 0x200));
   1059 #endif
   1060 
   1061     /*
   1062      * Configure 1000X control2 register (0x8301 Bit[7] = 1) to turn off
   1063      * carrier extension.  The Intel 7131 NIC does not accept carrier
   1064      * extension and gets CRC errors.
   1065      */
   1066     if(pc->lane_num == 0){
   1067          /* The phy address of QSGMII is the phy address pins + 8 */
   1068         pc->phy_id =  pc->phy_id + 8;
   1069 
   1070         SOC_IF_ERROR_RETURN   
   1071            (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS,   
   1072                                      0x0000, 0x1f, 0xffd0));   
   1073         SOC_IF_ERROR_RETURN   
   1074            (PHY54682_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f));   
   1075         SOC_IF_ERROR_RETURN   
   1076            (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS,   
   1077                                      0x0000, 0x1f, 0x8300));   
   1078         SOC_IF_ERROR_RETURN   
   1079            (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x11, 0x0080, 0x0080));
   1080 
   1081         /* QSGMII FIFO settings */
   1082         SOC_IF_ERROR_RETURN   
   1083            (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS,   
   1084                                      0x0000, 0x1f, 0xffd0));   
   1085         SOC_IF_ERROR_RETURN   
   1086            (PHY54682_REG_WRITE(unit, pc, 0x00, 0x0000, 0x1e, 0x1f));   
   1087         SOC_IF_ERROR_RETURN   
   1088            (PHY54682_REG_WRITE(unit, pc, SOC_PHY_REG_RESERVE_ACCESS,   
   1089                                      0x0000, 0x1f, 0x8330));   
   1090         SOC_IF_ERROR_RETURN   
   1091            (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0000, 0x1c, 0x0080, 0x0080));
   1092 
   1093 
   1094         if (PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc)) {
   1095             /* Enable LPI pass through on PHY for native EEE */
   1096             SOC_IF_ERROR_RETURN   
   1097                (phy_reg_aer_modify(unit, pc, 0x833e, 0xc000, 0xc000));
   1098         }
   1099 
   1100         /* Revert the phy_id */
   1101         pc->phy_id = pc->phy_id - 8;
   1102     }
   1103 
   1104     /* Configure extended control register for led mode and jumbo frame support
   1105      */
   1106     mask  = (1 << 5) | (1 << 0);
   1107 
   1108     /* if using led link/activity mode, disable led traffic mode */
   1109     if (pc->ledctrl & 0x10 || pc->ledselect == 0x01) {
   1110         data = 0;
   1111     } else {
   1112         data  = 1 << 5;      /* Enable LEDs to indicate traffic status */
   1113     }
   1114     /* Configure Extended Control Register for Jumbo frames support */
   1115     data |= 1 << 0;      /* Set high FIFO elasticity to support jumbo frames */
   1116     SOC_IF_ERROR_RETURN
   1117         (MODIFY_PHY54682_MII_ECRr(unit, pc, data, mask));
   1118 
   1119     /* Enable extended packet length (4.5k through 25k) */
   1120     SOC_IF_ERROR_RETURN
   1121         (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000));
   1122 
   1123     SOC_IF_ERROR_RETURN
   1124         (MODIFY_PHY54682_MISC_1000X_CTRL2r(unit, pc, 0x0001, 0x0001));
   1125 
   1126     SOC_IF_ERROR_RETURN
   1127         (MODIFY_PHY54682_AUX_CTRLr(unit, pc, 0x0002, 0x0002));
   1128 
   1129     /* Configure LED selectors */
   1130     data = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[0] & 0xf);
   1131     SOC_IF_ERROR_RETURN
   1132         (WRITE_PHY54682_LED_SELECTOR_1r(unit, pc, data));
   1133 
   1134     data = ((pc->ledmode[3] & 0xf) << 4) | (pc->ledmode[2] & 0xf);
   1135     SOC_IF_ERROR_RETURN
   1136         (WRITE_PHY54682_LED_SELECTOR_2r(unit, pc, data));
   1137 
   1138     data = (pc->ledctrl & 0x3ff);
   1139     SOC_IF_ERROR_RETURN
   1140         (WRITE_PHY54682_LED_CTRLr(unit, pc, data));
   1141 
   1142     SOC_IF_ERROR_RETURN
   1143         (WRITE_PHY54682_EXP_LED_SELECTORr(unit, pc, pc->ledselect));
   1144 
   1145     if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   1146         return SOC_E_NONE;
   1147     }
   1148 
   1149     /* 100BASE-TX initialization change for EEE and autogreen mode */
   1150     SOC_IF_ERROR_RETURN
   1151         (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00));
   1152     SOC_IF_ERROR_RETURN(
   1153         WRITE_PHY_REG(unit, pc, 0x17, 0x4022));
   1154     SOC_IF_ERROR_RETURN(
   1155         WRITE_PHY_REG(unit, pc, 0x15, 0x017b));
   1156     SOC_IF_ERROR_RETURN
   1157         (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00));
   1158 
   1159     return SOC_E_NONE;
   1160 }
   1161 
   1162 /*
   1163  * Function:
   1164  *      phy_54682_init
   1165  * Purpose:
   1166  *      Init function for 54682 PHY.
   1167  * Parameters:
   1168  *      unit - StrataSwitch unit #.
   1169  *      port - StrataSwitch port #.
   1170  * Returns:
   1171  *      SOC_E_NONE
   1172  */
   1173 
   1174 STATIC int
   1175 phy_54682_init(int unit, soc_port_t port)
   1176 {
   1177     phy_ctrl_t        *pc;
   1178     int                 fiber_capable;
   1179     int                 fiber_preferred;
   1180 
   1181     LOG_INFO(BSL_LS_SOC_PHY,
   1182              (BSL_META_U(unit,
   1183                          "phy_54682_init: u=%d p=%d\n"),
   1184                          unit, port));
   1185 
   1186     /* Only SGMII interface to switch MAC is supported */ 
   1187     if (IS_GMII_PORT(unit, port)) {
   1188         return SOC_E_CONFIG; 
   1189     }
   1190 
   1191     pc = EXT_PHY_SW_STATE(unit, port);
   1192     pc->interface = SOC_PORT_IF_SGMII;
   1193 
   1194     fiber_capable = 1;
   1195 
   1196     fiber_preferred =
   1197         soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 0);
   1198     pc->automedium =
   1199         soc_property_port_get(unit, port, spn_PHY_AUTOMEDIUM, 0);
   1200     pc->fiber_detect =
   1201         soc_property_port_get(unit, port, spn_PHY_FIBER_DETECT, -4);
   1202 
   1203     LOG_INFO(BSL_LS_SOC_PHY,
   1204              (BSL_META_U(unit,
   1205                          "phy_54682_init: "
   1206                          "u=%d p=%d type=54682%s automedium=%d fiber_pref=%d detect=%d\n"),
   1207               unit, port, fiber_capable ? "S" : "",
   1208               pc->automedium, fiber_preferred, pc->fiber_detect));
   1209 
   1210     pc->copper.enable = TRUE;
   1211     pc->copper.preferred = !fiber_preferred;
   1212     pc->copper.autoneg_enable = TRUE;
   1213     pc->copper.autoneg_advert = ADVERT_ALL_COPPER;
   1214     SOC_IF_ERROR_RETURN
   1215         (_phy_54682_ability_cu_local_get(unit, port, &(pc->copper.advert_ability)));
   1216     pc->copper.force_speed = 1000;
   1217     pc->copper.force_duplex = TRUE;
   1218     pc->copper.master = SOC_PORT_MS_AUTO;
   1219     pc->copper.mdix = SOC_PORT_MDIX_AUTO;
   1220 
   1221     pc->fiber.enable = fiber_capable;
   1222     pc->fiber.preferred = fiber_preferred;
   1223     pc->fiber.autoneg_enable = fiber_capable;
   1224     pc->fiber.autoneg_advert = ADVERT_ALL_FIBER;
   1225     SOC_IF_ERROR_RETURN
   1226         (_phy_54682_ability_fiber_local_get(unit, port, &(pc->fiber.advert_ability)));
   1227     pc->copper.advert_ability.medium = SOC_PA_MEDIUM_FIBER;
   1228     pc->fiber.force_speed = 1000;
   1229     pc->fiber.force_duplex = TRUE;
   1230     pc->fiber.master = SOC_PORT_MS_NONE;
   1231     pc->fiber.mdix = SOC_PORT_MDIX_NORMAL;
   1232 
   1233     /* Initially configure for the preferred medium. */
   1234     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER);
   1235     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
   1236     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU);
   1237     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
   1238     PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   1239     PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE);
   1240 
   1241     if (pc->fiber.preferred) {
   1242         PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
   1243     } else {
   1244         PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER);
   1245     }
   1246 
   1247     /* Get Requested LED selectors (defaults are hardware defaults) */
   1248     pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0);
   1249     pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1);
   1250     pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3);
   1251     pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6);
   1252     pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8);
   1253     pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0);
   1254 
   1255     SOC_IF_ERROR_RETURN
   1256         (_phy_54682_reset_setup(unit, port));
   1257 
   1258     SOC_IF_ERROR_RETURN
   1259         (_phy_54682_medium_config_update(unit, port,
   1260                                         PHY_COPPER_MODE(unit, port) ?
   1261                                         &pc->copper :
   1262                                         &pc->fiber));
   1263     return SOC_E_NONE;
   1264 }
   1265 
   1266 /*
   1267  * Function:
   1268  *      phy_54682_enable_set
   1269  * Purpose:
   1270  *      Enable or disable the physical interface.
   1271  * Parameters:
   1272  *      unit - StrataSwitch unit #.
   1273  *      port - StrataSwitch port #.
   1274  *      enable - Boolean, true = enable PHY, false = disable.
   1275  * Returns:
   1276  *      SOC_E_XXX
   1277  */
   1278 
   1279 STATIC int
   1280 phy_54682_enable_set(int unit, soc_port_t port, int enable)
   1281 {
   1282     uint16         power, mii_stat;
   1283     soc_timeout_t  to;
   1284     phy_ctrl_t    *pc;
   1285 
   1286     pc     = EXT_PHY_SW_STATE(unit, port);
   1287     power  = (enable) ? 0 : MII_CTRL_PD;
   1288 
   1289     /* Do not incorrectly Power up the interface if medium is disabled and 
   1290      * global enable = true
   1291      */
   1292     if (pc->copper.enable && (pc->automedium || PHY_COPPER_MODE(unit, port))) {
   1293         SOC_IF_ERROR_RETURN
   1294             (MODIFY_PHY54682_MII_CTRLr(unit, pc, power, MII_CTRL_PD));
   1295 
   1296         if (!enable) {
   1297             if ((PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) &&
   1298                ((pc->phy_rev & 0x4) == 0x0) ){ /* A0,A1,B0,B1 */
   1299                 soc_timeout_init(&to, 2000000, 0);
   1300                 do {
   1301                     SOC_IF_ERROR_RETURN
   1302                         (READ_PHY54682_MII_STATr(unit, pc, &mii_stat));
   1303                     if (soc_timeout_check(&to)) {
   1304                         LOG_WARN(BSL_LS_SOC_PHY,
   1305                                  (BSL_META_U(unit,
   1306                                              "phy54682.c: copper link didn't go down after power down: u=%d p=%d\n"),
   1307                                   unit, port));
   1308                         break;
   1309                     }
   1310                 } while(mii_stat & MII_STAT_LA);
   1311             }
   1312         }
   1313 
   1314         LOG_INFO(BSL_LS_SOC_PHY,
   1315                  (BSL_META_U(unit,
   1316                              "phy_54682_enable_set: "
   1317                              "Power %s copper medium\n"), (enable) ? "up" : "down"));
   1318     }
   1319 
   1320     if (pc->fiber.enable && (pc->automedium || PHY_FIBER_MODE(unit, port))) {
   1321         SOC_IF_ERROR_RETURN(
   1322             _phy_54685_fiber_power_control(unit, pc, enable) );
   1323         /*
   1324          * When enable/disable the fiber port,
   1325          * the Tx disable bit of Expansion register 0x52 should be set also.
   1326          * Otherwise the following issue happens.
   1327          * After the fiber port is powered down
   1328          * (verified bit 11 MII cotnrol register 0 is set to 1),
   1329          * the link partner still shows linkup
   1330          */
   1331         SOC_IF_ERROR_RETURN
   1332             (MODIFY_PHY54682_EXP_SERDES_SGMII_RX_CTRLr(unit, pc, enable?0:1, 0x1));
   1333         SOC_IF_ERROR_RETURN
   1334             (MODIFY_PHY54682_EXP_SERDES_SGMII_CTRLr(unit, pc, enable?0:1, 0x1));
   1335 
   1336         if (!enable) {
   1337             soc_timeout_init(&to, 2000000, 0);
   1338             do {
   1339                 SOC_IF_ERROR_RETURN
   1340                     (READ_PHY54682_1000X_MII_STATr(unit, pc, &mii_stat));
   1341 
   1342                 if (soc_timeout_check(&to)) {
   1343                     LOG_WARN(BSL_LS_SOC_PHY,
   1344                              (BSL_META_U(unit,
   1345                                          "phy54682.c: fiber link didn't go down after power down: u=%d p=%d\n"),
   1346                               unit, port));
   1347                     break;
   1348                 }
   1349             } while(mii_stat & MII_STAT_LA);
   1350         }
   1351 
   1352         LOG_INFO(BSL_LS_SOC_PHY,
   1353                  (BSL_META_U(unit,
   1354                              "phy_54682_enable_set: "
   1355                              "Power %s fiber medium\n"), (enable) ? "up" : "down"));
   1356     }
   1357 
   1358     /* Update software state */
   1359     SOC_IF_ERROR_RETURN(phy_fe_ge_enable_set(unit, port, enable));
   1360 
   1361     return SOC_E_NONE;
   1362 }
   1363 
   1364 /*
   1365  * Function:
   1366  *      phy_54682_enable_get
   1367  * Purpose:
   1368  *      Enable or disable the physical interface for a 54682 device.
   1369  * Parameters:
   1370  *      unit - StrataSwitch unit #.
   1371  *      port - StrataSwitch port #.
   1372  *      enable - (OUT) Boolean, true = enable PHY, false = disable.
   1373  * Returns:
   1374  *      SOC_E_XXX
   1375  */
   1376 
   1377 STATIC int
   1378 phy_54682_enable_get(int unit, soc_port_t port, int *enable)
   1379 {
   1380     return phy_fe_ge_enable_get(unit, port, enable);
   1381 }
   1382 
   1383 /*
   1384  * Function:
   1385  *      _phy_54682_fiber_100fx_setup
   1386  * Purpose:
   1387  *      Switch from 1000X mode to 100FX.  
   1388  * Parameters:
   1389  *      unit - StrataSwitch unit #.
   1390  *      port - StrataSwitch port #.
   1391  * Returns:
   1392  *      SOC_E_XXX
   1393  */
   1394 STATIC int
   1395 _phy_54682_fiber_100fx_setup(int unit, soc_port_t port) 
   1396 {
   1397     phy_ctrl_t    *pc;
   1398 
   1399     pc          = EXT_PHY_SW_STATE(unit, port);
   1400 
   1401     LOG_VERBOSE(BSL_LS_SOC_PHY,
   1402                 (BSL_META_U(unit,
   1403                             "_phy_54682_1000x_to_100fx: u=%d p=%d \n"),
   1404                  unit, port));
   1405 
   1406     /* Power up the SerDes      */
   1407     SOC_IF_ERROR_RETURN(
   1408         _phy_54685_fiber_power_control(unit, pc,
   1409                 PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)
   1410                 ? FIBER_POWER_DOWN : FIBER_POWER_UP) );
   1411 
   1412     /* Operate SerDes in 100FX  */
   1413 
   1414     /* SerDes 100FX control register - register 1CH shadow 13H             *\
   1415     \* bit[0]: 100FX link SerDes enable , bit[1]: 100FX SerDes full duplex */
   1416     if(pc->fiber.force_duplex) {
   1417         SOC_IF_ERROR_RETURN
   1418                 (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, 0x3, 0x3));
   1419     } else {
   1420         SOC_IF_ERROR_RETURN
   1421                 (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, 0x1, 0x3));
   1422     }
   1423 
   1424     /* Set speed/AN/duplex.   1000-x MII Control  Reg. (1000X Reg. 00h) */
   1425     SOC_IF_ERROR_RETURN
   1426         (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc, 
   1427                         MII_CTRL_AE | MII_CTRL_FD | MII_CTRL_SS_100) );
   1428 
   1429     PHY_FLAGS_SET(unit, port, PHY_FLAGS_100FX);
   1430     pc->fiber.autoneg_enable = FALSE;
   1431 
   1432     return SOC_E_NONE;
   1433 }
   1434 
   1435 /*
   1436  * Function:
   1437  *      _phy_54682_fiber_1000x_setup
   1438  * Purpose:
   1439  *      Switch from 100FX mode to 1000X.  
   1440  * Parameters:
   1441  *      unit - StrataSwitch unit #.
   1442  *      port - StrataSwitch port #.
   1443  * Returns:
   1444  *      SOC_E_XXX
   1445  */
   1446 STATIC int
   1447 _phy_54682_fiber_1000x_setup(int unit, soc_port_t port) 
   1448 {
   1449     uint16         data;
   1450     phy_ctrl_t    *pc;
   1451 
   1452     pc          = EXT_PHY_SW_STATE(unit, port);
   1453 
   1454     LOG_VERBOSE(BSL_LS_SOC_PHY,
   1455                 (BSL_META_U(unit,
   1456                             "_phy_54682_fiber_1000x_setup: u=%d p=%d \n"),
   1457                  unit, port));
   1458 
   1459     /* Power up the SerDes      */
   1460     SOC_IF_ERROR_RETURN(
   1461         _phy_54685_fiber_power_control(unit, pc,
   1462                 PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)
   1463                 ? FIBER_POWER_DOWN : FIBER_POWER_UP) );
   1464 
   1465     /* Operate SerDes in 1000X  */
   1466     SOC_IF_ERROR_RETURN
   1467             (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, 0x0, 0x1));
   1468     if (pc->fiber.autoneg_enable) {
   1469         data = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000;
   1470     } else {
   1471         data = MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000;
   1472     }
   1473     SOC_IF_ERROR_RETURN
   1474         (WRITE_PHY54682_1000X_MII_CTRLr(unit, pc, data));
   1475 
   1476     /* When speed is 1000Mbps, set duplex to HD mode.           *\
   1477     \* This is because our MAC does not support 1G half duplex. */
   1478     pc->fiber.force_duplex = TRUE;
   1479     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
   1480 
   1481     return SOC_E_NONE;
   1482 }
   1483 
   1484 STATIC int
   1485 _phy_54682_medium_change(int unit, soc_port_t port, int force_update)
   1486 {
   1487     phy_ctrl_t    *pc;
   1488     int            medium;
   1489 
   1490     pc    = EXT_PHY_SW_STATE(unit, port);
   1491 
   1492     SOC_IF_ERROR_RETURN
   1493         (_phy_54682_medium_check(unit, port, &medium));
   1494 
   1495     if (medium == SOC_PORT_MEDIUM_COPPER) {
   1496         if ((!PHY_COPPER_MODE(unit, port)) || force_update) { /* Was fiber */ 
   1497             PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER);
   1498             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
   1499             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
   1500             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1501             /* BCM54682E is EEE capable */
   1502             if (PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc)) {
   1503                 PHY_FLAGS_SET(unit, port, PHY_FLAGS_EEE_CAPABLE);
   1504             }
   1505             SOC_IF_ERROR_RETURN
   1506                 (_phy_54682_no_reset_setup(unit, port));
   1507 
   1508             /* Do not power up the interface if medium is disabled. */
   1509             if (pc->copper.enable) {
   1510                 SOC_IF_ERROR_RETURN
   1511                     (_phy_54682_medium_config_update(unit, port, &pc->copper));
   1512             }
   1513             LOG_INFO(BSL_LS_SOC_PHY,
   1514                      (BSL_META_U(unit,
   1515                                  "_phy_54682_link_auto_detect: u=%d p=%d [F->C]\n"),
   1516                       unit, port));
   1517         }
   1518 
   1519     } else {        /* Fiber */
   1520         if (PHY_COPPER_MODE(unit, port) || force_update) { /* Was copper */
   1521             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER);
   1522             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_EEE_CAPABLE);
   1523             PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
   1524             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1525             SOC_IF_ERROR_RETURN
   1526                 (_phy_54682_no_reset_setup(unit, port));
   1527 
   1528             /*
   1529              * When enable/disable the fiber port,
   1530              * the Tx disable bit of Expansion register 0x52 should be set also.
   1531              * Otherwise the following issue happens.
   1532              * After the fiber port is powered down
   1533              * (verified bit 11 MII cotnrol register 0 is set to 1),
   1534              * the link partner still shows linkup
   1535              */
   1536             SOC_IF_ERROR_RETURN
   1537                 (MODIFY_PHY54682_EXP_SERDES_SGMII_RX_CTRLr(unit, pc,
   1538                                                  pc->fiber.enable?0:1, 0x1));
   1539             SOC_IF_ERROR_RETURN
   1540                 (MODIFY_PHY54682_EXP_SERDES_SGMII_CTRLr(unit, pc,
   1541                                                  pc->fiber.enable?0:1, 0x1));
   1542 
   1543             if (pc->fiber.enable) {
   1544                 SOC_IF_ERROR_RETURN
   1545                     (_phy_54682_medium_config_update(unit, port, &pc->fiber));
   1546             }
   1547             LOG_INFO(BSL_LS_SOC_PHY,
   1548                      (BSL_META_U(unit,
   1549                                  "_phy_54682_link_auto_detect: u=%d p=%d [C->F]\n"),
   1550                       unit, port));
   1551         }
   1552     }
   1553     return SOC_E_NONE;
   1554 }
   1555 
   1556 /*
   1557  * Function:
   1558  *      phy_54682_link_get
   1559  * Purpose:
   1560  *      Determine the current link up/down status for a 54682 device.
   1561  * Parameters:
   1562  *      unit - StrataSwitch unit #.
   1563  *      port - StrataSwitch port #.
   1564  *      link - (OUT) Boolean, true indicates link established.
   1565  * Returns:
   1566  *      SOC_E_XXX
   1567  * Notes:
   1568  *      If using automedium, also switches the mode.
   1569  */
   1570 STATIC int
   1571 phy_54682_link_get(int unit, soc_port_t port, int *link)
   1572 {
   1573     phy_ctrl_t    *pc;
   1574     uint16         data; 
   1575     uint16         mask;
   1576 
   1577     pc    = EXT_PHY_SW_STATE(unit, port);
   1578     *link = FALSE;      /* Default return */
   1579 
   1580     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
   1581         return SOC_E_NONE;
   1582     }
   1583 
   1584     if (!pc->fiber.enable && !pc->copper.enable) {
   1585         return SOC_E_NONE;
   1586     }
   1587 
   1588     SOC_IF_ERROR_RETURN
   1589         (READ_PHY54682_EXP_OPT_MODE_STATr(unit, pc, &data));
   1590 
   1591     if (!(data & (1U << 5))) { /* no sync */
   1592         SOC_IF_ERROR_RETURN
   1593             (READ_PHY54682_1000X_MII_ANPr(unit, pc, &data));
   1594 
   1595         if (data & MII_ANP_SGMII_MODE) { /* Link partner is SGMII master */
   1596             /* Disable auto-detection between SGMII-slave and 1000BASE-X and set mode to 1000BASE-X */
   1597             SOC_IF_ERROR_RETURN
   1598                    (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 0, 0x3));
   1599 
   1600             /* Now enable auto-detection between SGMII-slave and 1000BASE-X */
   1601             SOC_IF_ERROR_RETURN
   1602                    (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 1, 1));
   1603         }
   1604     }
   1605 
   1606     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1607     if ( pc->automedium ) {
   1608         /* Check for medium change and update HW/SW accordingly. */
   1609         SOC_IF_ERROR_RETURN
   1610             (_phy_54682_medium_change(unit, port,FALSE));
   1611     }
   1612     if (PHY_COPPER_MODE(unit, port)) {
   1613         SOC_IF_ERROR_RETURN(phy_fe_ge_link_get(unit, port, link));
   1614     } else {
   1615         SOC_IF_ERROR_RETURN
   1616             (READ_PHY54682_1000X_MII_STATr(unit, pc, &data));
   1617         *link = (data & MII_STAT_LA) ? TRUE : FALSE;
   1618     }
   1619 
   1620     /* If preferred medium is up, disable the other medium 
   1621      * to prevent false link. */
   1622     if ( pc->automedium ) {
   1623         mask = MII_CTRL_PD;
   1624 
   1625         if ( pc->copper.preferred ) {
   1626             if ( pc->fiber.enable ) {
   1627                 /* power down the serdes if copper preferred && copper is up */
   1628                 data = (*link && PHY_COPPER_MODE(unit, port))
   1629                        ? FIBER_POWER_DOWN : FIBER_POWER_UP;
   1630             } else {
   1631                 /* fiber is disabled, power down the serdes */
   1632                 data = FIBER_POWER_DOWN;
   1633             }
   1634             SOC_IF_ERROR_RETURN(
   1635                 _phy_54685_fiber_power_control(unit, pc, data) );
   1636 
   1637         } else {  /* pc->fiber.preferred */
   1638             if ( pc->copper.enable ) {
   1639                 data = (*link && PHY_FIBER_MODE(unit, port)) ? MII_CTRL_PD : 0;
   1640             } else {
   1641                 data = MII_CTRL_PD;
   1642             }
   1643             SOC_IF_ERROR_RETURN
   1644                 (MODIFY_PHY54682_MII_CTRLr(unit, pc, data, mask));
   1645         }
   1646     }
   1647 
   1648     LOG_VERBOSE(BSL_LS_SOC_PHY,
   1649                 (BSL_META_U(unit,
   1650                             "phy_54682_link_get: u=%d p=%d mode=%s%s link=%d\n"),
   1651                  unit, port,
   1652                  PHY_COPPER_MODE(unit, port) ? "C" : "F",
   1653                  PHY_FIBER_100FX_MODE(unit, port)? "(100FX)" : "",
   1654                  *link));
   1655 
   1656     return SOC_E_NONE;
   1657 }
   1658 
   1659 /*
   1660  * Function:
   1661  *      phy_54682_duplex_set
   1662  * Purpose:
   1663  *      Set the current duplex mode (forced).
   1664  * Parameters:
   1665  *      unit - StrataSwitch unit #.
   1666  *      port - StrataSwitch port #.
   1667  *      duplex - Boolean, true indicates full duplex, false indicates half.
   1668  * Returns:
   1669  *      SOC_E_NONE
   1670  *      SOC_E_UNAVAIL - Half duplex requested, and not supported.
   1671  * Notes:
   1672  *      The duplex is set only for the ACTIVE medium.
   1673  *      No synchronization performed at this level.
   1674  *      Autonegotiation is not manipulated.
   1675  */
   1676 
   1677 STATIC int
   1678 phy_54682_duplex_set(int unit, soc_port_t port, int duplex)
   1679 {
   1680     int                  rv;
   1681     phy_ctrl_t    *pc;
   1682 
   1683     pc = EXT_PHY_SW_STATE(unit, port);
   1684     rv = SOC_E_NONE;
   1685     if (PHY_COPPER_MODE(unit, port)) {
   1686         /* Note: mac.c uses phy_5690_notify_duplex to update 5690 */
   1687         rv = phy_fe_ge_duplex_set(unit, port, duplex);
   1688         if (SOC_SUCCESS(rv)) {
   1689             pc->copper.force_duplex = duplex;
   1690         }
   1691     } else {    /* Fiber */
   1692         if (PHY_FIBER_100FX_MODE(unit, port)) {
   1693             SOC_IF_ERROR_RETURN
   1694                 (MODIFY_PHY54682_SERDES_100FX_CTRLr(unit, pc, duplex? 0x2:0x0, 0x2));
   1695             pc->fiber.force_duplex = duplex;
   1696         } else {
   1697             if(!duplex) {
   1698                 return SOC_E_UNAVAIL;
   1699             }
   1700         }
   1701     }
   1702 
   1703     LOG_INFO(BSL_LS_SOC_PHY,
   1704              (BSL_META_U(unit,
   1705                          "phy_54682_duplex_set: u=%d p=%d d=%d rv=%d\n"),
   1706               unit, port, duplex, rv));
   1707 
   1708     return rv;
   1709 }
   1710 
   1711 /*
   1712  * Function:
   1713  *      phy_54682_duplex_get
   1714  * Purpose:
   1715  *      Get the current operating duplex mode. If autoneg is enabled,
   1716  *      then operating mode is returned, otherwise forced mode is returned.
   1717  * Parameters:
   1718  *      unit - StrataSwitch unit #.
   1719  *      port - StrataSwitch port #.
   1720  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1721  *              indicates half.
   1722  * Returns:
   1723  *      SOC_E_NONE
   1724  * Notes:
   1725  *      The duplex is retrieved for the ACTIVE medium.
   1726  *      No synchronization performed at this level. Autonegotiation is
   1727  *      not manipulated.
   1728  */
   1729 
   1730 STATIC int
   1731 phy_54682_duplex_get(int unit, soc_port_t port, int *duplex)
   1732 {
   1733     phy_ctrl_t    *pc;
   1734     uint16         opt_mode;
   1735 
   1736     pc = EXT_PHY_SW_STATE(unit, port);
   1737 
   1738     if (PHY_COPPER_MODE(unit, port)) {
   1739         return phy_fe_ge_duplex_get(unit, port, duplex);    
   1740     } else {    /* Fiber (1000BaseX, 100BaseFX, SGMII-Slave */
   1741         SOC_IF_ERROR_RETURN
   1742             (READ_PHY54682_EXP_OPT_MODE_STATr(unit, pc, &opt_mode));
   1743         /* The bit 12 of register EXP_OPT_MODE_STAT is serdes duplex */
   1744         *duplex = (opt_mode & 0x1000) ? TRUE : FALSE;
   1745     }
   1746         
   1747     return SOC_E_NONE;
   1748 }
   1749 
   1750 /*
   1751  * Function:
   1752  *      phy_54682_speed_set
   1753  * Purpose:
   1754  *      Set the current operating speed (forced).
   1755  * Parameters:
   1756  *      unit - StrataSwitch unit #.
   1757  *      port - StrataSwitch port #.
   1758  *      speed - Requested speed, only 1000 supported.
   1759  * Returns:
   1760  *      SOC_E_XXX
   1761  * Notes:
   1762  *      The speed is set only for the ACTIVE medium.
   1763  */
   1764 
   1765 STATIC int
   1766 phy_54682_speed_set(int unit, soc_port_t port, int speed)
   1767 {
   1768     int            rv; 
   1769     phy_ctrl_t    *pc;
   1770 
   1771     pc = EXT_PHY_SW_STATE(unit, port);
   1772     rv = SOC_E_NONE;
   1773     if (PHY_COPPER_MODE(unit, port)) {
   1774         /* Note: mac.c uses phy_5690_notify_speed to update 5690 */
   1775         rv = phy_fe_ge_speed_set(unit, port, speed);
   1776         if (SOC_SUCCESS(rv)) {
   1777             pc->copper.force_speed = speed;
   1778         }
   1779     } else {    /* Fiber */
   1780         if (speed == 100) {
   1781             rv = _phy_54682_fiber_100fx_setup(unit, port);
   1782         } else  if (speed == 0 || speed == 1000) {
   1783             rv = _phy_54682_fiber_1000x_setup(unit, port);
   1784         } else {
   1785             rv = SOC_E_CONFIG;
   1786         }
   1787         if (SOC_SUCCESS(rv)) {
   1788             pc->fiber.force_speed = speed;
   1789         }
   1790     }
   1791 
   1792     LOG_INFO(BSL_LS_SOC_PHY,
   1793              (BSL_META_U(unit,
   1794                          "phy_54682_speed_set: u=%d p=%d s=%d fiber=%d rv=%d\n"),
   1795               unit, port, speed, PHY_FIBER_MODE(unit, port), rv));
   1796 
   1797     return rv;
   1798 }
   1799 
   1800 /*
   1801  * Function:
   1802  *      phy_54682_speed_get
   1803  * Purpose:
   1804  *      Get the current operating speed for a 54682 device.
   1805  * Parameters:
   1806  *      unit - StrataSwitch unit #.
   1807  *      port - StrataSwitch port #.
   1808  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1809  *              indicates half.
   1810  * Returns:
   1811  *      SOC_E_NONE
   1812  * Notes:
   1813  *      The speed is retrieved for the ACTIVE medium.
   1814  */
   1815 
   1816 STATIC int
   1817 phy_54682_speed_get(int unit, soc_port_t port, int *speed)
   1818 {
   1819     phy_ctrl_t    *pc;
   1820     uint16         opt_mode;
   1821 
   1822     pc = EXT_PHY_SW_STATE(unit, port);
   1823 
   1824     if (PHY_COPPER_MODE(unit, port)) {
   1825         return phy_fe_ge_speed_get(unit, port, speed);
   1826     } else {
   1827         *speed = 1000;
   1828         SOC_IF_ERROR_RETURN
   1829             (READ_PHY54682_EXP_OPT_MODE_STATr(unit, pc, &opt_mode));
   1830         switch(opt_mode & (0x3 << 13)) {
   1831         case (0 << 13):
   1832             *speed = 10;
   1833             break;
   1834         case (1 << 13):
   1835             *speed = 100;
   1836             break;
   1837         case (2 << 13):
   1838             *speed = 1000;
   1839             break;
   1840         default:
   1841             LOG_WARN(BSL_LS_SOC_PHY,
   1842                      (BSL_META_U(unit,
   1843                                  "phy_54682_speed_get: u=%d p=%d invalid speed\n"),
   1844                       unit, port));
   1845         }
   1846     }
   1847 
   1848     return SOC_E_NONE;
   1849 }
   1850 
   1851 /*
   1852  * Function:
   1853  *      phy_54682_master_set
   1854  * Purpose:
   1855  *      Set the current master mode
   1856  * Parameters:
   1857  *      unit - StrataSwitch unit #.
   1858  *      port - StrataSwitch port #.
   1859  *      master - SOC_PORT_MS_*
   1860  * Returns:
   1861  *      SOC_E_XXX
   1862  * Notes:
   1863  *      The master mode is set only for the ACTIVE medium.
   1864  */
   1865 STATIC int
   1866 phy_54682_master_set(int unit, soc_port_t port, int master)
   1867 {
   1868     int                  rv;
   1869     phy_ctrl_t    *pc;
   1870 
   1871     pc = EXT_PHY_SW_STATE(unit, port);
   1872     rv = SOC_E_NONE;
   1873     if (PHY_COPPER_MODE(unit, port)) {
   1874         rv = phy_fe_ge_master_set(unit, port, master);
   1875         if (SOC_SUCCESS(rv)) {
   1876             pc->copper.master = master;
   1877         }
   1878     }
   1879     LOG_INFO(BSL_LS_SOC_PHY,
   1880              (BSL_META_U(unit,
   1881                          "phy_54682_master_set: u=%d p=%d master=%d fiber=%d rv=%d\n"),
   1882               unit, port, master, PHY_FIBER_MODE(unit, port), rv));
   1883     return rv;
   1884 }
   1885 
   1886 /*
   1887  * Function:
   1888  *      phy_54682_master_get
   1889  * Purpose:
   1890  *      Get the current master mode for a 54682 device.
   1891  * Parameters:
   1892  *      unit - StrataSwitch unit #.
   1893  *      port - StrataSwitch port #.
   1894  *      master - (OUT) SOC_PORT_MS_*
   1895  * Returns:
   1896  *      SOC_E_NONE
   1897  * Notes:
   1898  *      The master mode is retrieved for the ACTIVE medium.
   1899  */
   1900 
   1901 STATIC int
   1902 phy_54682_master_get(int unit, soc_port_t port, int *master)
   1903 {
   1904     if (PHY_COPPER_MODE(unit, port)) {
   1905         return phy_fe_ge_master_get(unit, port, master);
   1906     } else {
   1907         *master = SOC_PORT_MS_NONE;
   1908         return SOC_E_NONE;
   1909     }
   1910 }
   1911 
   1912 /*
   1913  * Function:
   1914  *      phy_54682_autoneg_set
   1915  * Purpose:
   1916  *      Enable or disable auto-negotiation on the specified port.
   1917  * Parameters:
   1918  *      unit - StrataSwitch unit #.
   1919  *      port - StrataSwitch port #.
   1920  *      autoneg - Boolean, if true, auto-negotiation is enabled
   1921  *              (and/or restarted). If false, autonegotiation is disabled.
   1922  * Returns:
   1923  *      SOC_E_XXX
   1924  * Notes:
   1925  *      The autoneg mode is set only for the ACTIVE medium.
   1926  */
   1927 
   1928 STATIC int
   1929 phy_54682_autoneg_set(int unit, soc_port_t port, int autoneg)
   1930 {
   1931     int                 rv;
   1932     uint16              data, mask;
   1933     phy_ctrl_t   *pc;
   1934 
   1935     pc = EXT_PHY_SW_STATE(unit, port);
   1936     rv = SOC_E_NONE;
   1937     if (PHY_COPPER_MODE(unit, port)) {
   1938         rv = phy_fe_ge_an_set(unit, port, autoneg);
   1939         if (SOC_SUCCESS(rv)) {
   1940             pc->copper.autoneg_enable = autoneg ? 1 : 0;
   1941         }
   1942     } else { 
   1943         if (autoneg) {
   1944             /* When enabling autoneg, set the default speed to 1000Mbps first.
   1945              * PHY will not enable autoneg if the PHY is in 100FX mode.
   1946              */
   1947             SOC_IF_ERROR_RETURN
   1948                 (phy_54682_speed_set(unit, port, 1000));
   1949         }
   1950 
   1951         /* Disable/Enable auto-detection between SGMII-slave and 1000BASE-X */
   1952         SOC_IF_ERROR_RETURN
   1953             (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, (autoneg ? 1 : 0), 1));
   1954 
   1955         SOC_IF_ERROR_RETURN
   1956             (phy_54682_ability_advert_set(unit, port,
   1957                                          &(pc->fiber.advert_ability)));
   1958         data = MII_CTRL_FD;
   1959         data |= (autoneg) ? MII_CTRL_AE | MII_CTRL_RAN : 0;
   1960         mask = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD;
   1961         SOC_IF_ERROR_RETURN
   1962             (MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc, data, mask));
   1963 
   1964         pc->fiber.autoneg_enable = autoneg ? TRUE : FALSE;
   1965     }
   1966  
   1967     LOG_INFO(BSL_LS_SOC_PHY,
   1968              (BSL_META_U(unit,
   1969                          "phy_54682_autoneg_set: u=%d p=%d autoneg=%d rv=%d\n"),
   1970               unit, port, autoneg, rv));
   1971 
   1972     return rv;
   1973 }
   1974 
   1975 /*
   1976  * Function:
   1977  *      phy_54682_autoneg_get
   1978  * Purpose:
   1979  *      Get the current auto-negotiation status (enabled/busy).
   1980  * Parameters:
   1981  *      unit - StrataSwitch unit #.
   1982  *      port - StrataSwitch port #.
   1983  *      autoneg - (OUT) if true, auto-negotiation is enabled.
   1984  *      autoneg_done - (OUT) if true, auto-negotiation is complete. This
   1985  *              value is undefined if autoneg == FALSE.
   1986  * Returns:
   1987  *      SOC_E_XXX
   1988  * Notes:
   1989  *      The autoneg mode is retrieved for the ACTIVE medium.
   1990  */
   1991 
   1992 STATIC int
   1993 phy_54682_autoneg_get(int unit, soc_port_t port,
   1994                      int *autoneg, int *autoneg_done)
   1995 {
   1996     int           rv;
   1997     uint16        data;
   1998     phy_ctrl_t   *pc;
   1999 
   2000     pc = EXT_PHY_SW_STATE(unit, port);
   2001 
   2002     rv            = SOC_E_NONE;
   2003     *autoneg      = FALSE;
   2004     *autoneg_done = FALSE;
   2005     if (PHY_COPPER_MODE(unit, port)) {
   2006         rv = phy_fe_ge_an_get(unit, port, autoneg, autoneg_done);
   2007     } else {
   2008         /* autoneg is not enabled in 100FX mode */
   2009         if (PHY_FIBER_100FX_MODE(unit, port)) {
   2010             *autoneg = FALSE;
   2011             *autoneg_done = TRUE;
   2012             return rv;
   2013         }
   2014 
   2015         SOC_IF_ERROR_RETURN
   2016             (READ_PHY54682_1000X_MII_CTRLr(unit, pc, &data));
   2017         if (data & MII_CTRL_AE) {
   2018             *autoneg = TRUE;
   2019 
   2020             SOC_IF_ERROR_RETURN
   2021                 (READ_PHY54682_1000X_MII_STATr(unit, pc, &data));
   2022             if (data & MII_STAT_AN_DONE) {
   2023                 *autoneg_done = TRUE;
   2024             }
   2025         }
   2026         
   2027     }
   2028 
   2029     return rv;
   2030 }
   2031 
   2032 /*
   2033  * Function:
   2034  *      phy_54682_ability_advert_set
   2035  * Purpose:
   2036  *      Set the current advertisement for auto-negotiation.
   2037  * Parameters:
   2038  *      unit    - StrataSwitch unit #.
   2039  *      port    - StrataSwitch port #.
   2040  *      ability - Port ability indicating supported options/speeds.
   2041  * Returns:
   2042  *      SOC_E_XXX
   2043  */
   2044 
   2045 STATIC int
   2046 phy_54682_ability_advert_set(int unit, soc_port_t port, soc_port_ability_t *ability)
   2047 {
   2048     int          rv;
   2049     phy_ctrl_t   *pc;
   2050     uint16       mii_adv, mii_gb_ctrl, eee_ability = 0;
   2051 
   2052     if ( NULL == ability ) {
   2053         return SOC_E_PARAM;
   2054     }
   2055 
   2056     pc = EXT_PHY_SW_STATE(unit, port);
   2057     rv = SOC_E_NONE;
   2058 
   2059     if ( PHY_COPPER_MODE(unit, port) ) {
   2060         mii_adv = MII_ANA_ASF_802_3;
   2061 
   2062         SOC_IF_ERROR_RETURN
   2063             (READ_PHY54682_MII_GB_CTRLr(unit, pc,  &mii_gb_ctrl));
   2064 
   2065         mii_gb_ctrl &= ~(MII_GB_CTRL_ADV_1000HD | MII_GB_CTRL_ADV_1000FD);
   2066         mii_gb_ctrl |= MII_GB_CTRL_PT; /* repeater / switch port */
   2067 
   2068         if (ability->speed_half_duplex & SOC_PA_SPEED_10MB)  {
   2069             mii_adv |= MII_ANA_HD_10;
   2070         }
   2071         if (ability->speed_half_duplex & SOC_PA_SPEED_100MB) {
   2072             mii_adv |= MII_ANA_HD_100;
   2073         }
   2074         if (ability->speed_half_duplex & SOC_PA_SPEED_1000MB) {
   2075             mii_gb_ctrl |= MII_GB_CTRL_ADV_1000HD;
   2076         }
   2077         if (ability->speed_full_duplex & SOC_PA_SPEED_10MB)  {
   2078             mii_adv |= MII_ANA_FD_10;
   2079         }
   2080         if (ability->speed_full_duplex & SOC_PA_SPEED_100MB) {
   2081             mii_adv |= MII_ANA_FD_100;
   2082         }
   2083         if (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) {
   2084             mii_gb_ctrl |= MII_GB_CTRL_ADV_1000FD;
   2085         }
   2086 
   2087         switch ( ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX) ) {
   2088         case SOC_PA_PAUSE_TX:
   2089             mii_adv |= MII_ANA_ASYM_PAUSE;
   2090             break;
   2091         case SOC_PA_PAUSE_RX:
   2092             mii_adv |= MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE;
   2093             break;
   2094         case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   2095             mii_adv |= MII_ANA_PAUSE;
   2096             break;
   2097         }
   2098 
   2099         /* EEE settings */
   2100         if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2101             eee_ability = 0;
   2102             if (ability->eee & SOC_PA_EEE_1GB_BASET) {
   2103                 eee_ability |= 0x4;
   2104             }
   2105             if (ability->eee & SOC_PA_EEE_100MB_BASETX) {
   2106                 eee_ability |= 0x2;
   2107             }
   2108             if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED)) {
   2109                 SOC_IF_ERROR_RETURN
   2110                     (MODIFY_PHY54682_EEE_ADVr(unit, pc, eee_ability, 0x0006));
   2111             } else {
   2112                 SOC_IF_ERROR_RETURN
   2113                     (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0000, 0x0006));
   2114             }
   2115         }
   2116 
   2117         SOC_IF_ERROR_RETURN
   2118             (MODIFY_PHY54682_MII_ANAr(unit, pc, mii_adv,
   2119             MII_ANA_PAUSE|MII_ANA_ASYM_PAUSE|MII_ANA_FD_100|MII_ANA_HD_100|
   2120             MII_ANA_FD_10|MII_ANA_HD_10|MII_ANA_ASF_802_3));
   2121 
   2122         SOC_IF_ERROR_RETURN
   2123             (MODIFY_PHY54682_MII_GB_CTRLr(unit, pc, mii_gb_ctrl,
   2124             MII_GB_CTRL_PT|MII_GB_CTRL_ADV_1000FD|MII_GB_CTRL_ADV_1000HD));
   2125 
   2126         /* update the PHY property software table (phy_ctrl_t) */
   2127         sal_memcpy( &(pc->copper.advert_ability), ability,
   2128                     sizeof(soc_port_ability_t) );
   2129 
   2130     } else {    /* PHY_FIBER_MODE */
   2131         mii_adv = MII_ANA_C37_FD;    /* Always advertise 1000X full duplex */
   2132 
   2133         switch ( ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX) ) {
   2134         case SOC_PA_PAUSE_TX:
   2135             mii_adv |= MII_ANA_C37_ASYM_PAUSE;
   2136             break;
   2137         case SOC_PA_PAUSE_RX:
   2138             mii_adv |= (MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE);
   2139             break;
   2140         case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
   2141             mii_adv |= MII_ANA_C37_PAUSE;
   2142             break;
   2143         }
   2144         /* Write to SerDes Auto-Neg Advertisement Reg */
   2145         rv = WRITE_PHY54682_1000X_MII_ANAr(unit, pc, mii_adv);
   2146 
   2147         /* update the PHY property software table (phy_ctrl_t) */
   2148         sal_memcpy( &(pc->fiber.advert_ability), ability,
   2149                     sizeof(soc_port_ability_t) );
   2150     }
   2151     return rv;
   2152 }
   2153 
   2154 /*
   2155  * Function:
   2156  *      phy_54682_ability_advert_get
   2157  * Purpose:
   2158  *      Get the current advertisement for auto-negotiation.
   2159  * Parameters:
   2160  *      unit    - StrataSwitch unit #.
   2161  *      port    - StrataSwitch port #.
   2162  *      ability - Port ability indicating supported options/speeds.
   2163  * Returns:
   2164  *      SOC_E_XXX
   2165  * Notes:
   2166  *      The advertisement is retrieved for the ACTIVE medium.
   2167  *      No synchronization performed at this level.
   2168  */
   2169 
   2170 STATIC int
   2171 phy_54682_ability_advert_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2172 {
   2173     phy_ctrl_t *pc;
   2174     uint16      mii_ana;
   2175     uint16      mii_gb_ctrl;
   2176     uint16      eee_ability = 0;
   2177 
   2178     if (NULL == ability) {
   2179         return (SOC_E_PARAM);
   2180     }
   2181 
   2182     pc = EXT_PHY_SW_STATE(unit, port);
   2183 
   2184     if (PHY_COPPER_MODE(unit, port)) {
   2185 
   2186         SOC_IF_ERROR_RETURN
   2187             (READ_PHY54682_MII_ANAr(unit, pc, &mii_ana));
   2188         SOC_IF_ERROR_RETURN
   2189             (READ_PHY54682_MII_GB_CTRLr(unit, pc, &mii_gb_ctrl));
   2190 
   2191         sal_memset(ability, 0, sizeof(*ability));
   2192 
   2193         if (mii_ana & MII_ANA_HD_10) {
   2194            ability->speed_half_duplex |= SOC_PA_SPEED_10MB;
   2195         }
   2196         if (mii_ana & MII_ANA_HD_100) {
   2197           ability->speed_half_duplex |= SOC_PA_SPEED_100MB;
   2198         }
   2199         if (mii_ana & MII_ANA_FD_10) {
   2200           ability->speed_full_duplex |= SOC_PA_SPEED_10MB;
   2201         }
   2202         if (mii_ana & MII_ANA_FD_100) {
   2203           ability->speed_full_duplex |= SOC_PA_SPEED_100MB;
   2204         }
   2205 
   2206         switch (mii_ana & (MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE)) {
   2207         case MII_ANA_PAUSE:
   2208             ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   2209             break;
   2210         case MII_ANA_ASYM_PAUSE:
   2211             ability->pause = SOC_PA_PAUSE_TX;
   2212             break;
   2213         case MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE:
   2214             ability->pause = SOC_PA_PAUSE_RX;
   2215             break;
   2216         }
   2217 
   2218         /* GE Specific values */
   2219 
   2220         if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000HD) {
   2221            ability->speed_half_duplex |= SOC_PA_SPEED_1000MB;
   2222         }
   2223         if (mii_gb_ctrl & MII_GB_CTRL_ADV_1000FD) {
   2224            ability->speed_full_duplex |= SOC_PA_SPEED_1000MB;
   2225         }
   2226 
   2227         /* EEE settings */
   2228         if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2229             SOC_IF_ERROR_RETURN
   2230                 (READ_PHY54682_EEE_ADVr(unit, pc, &eee_ability));
   2231             if (eee_ability & 0x04) {
   2232                 ability->eee |= SOC_PA_EEE_1GB_BASET;
   2233             }
   2234             if (eee_ability & 0x02) {
   2235                 ability->eee |= SOC_PA_EEE_100MB_BASETX;
   2236             }
   2237         }
   2238     } else {    /* PHY_FIBER_MODE */
   2239         uint16  mii_adv;
   2240 
   2241         /* read the 1000BASE-X Auto-Neg Advertisement Reg ( Address 0x04 ) */
   2242         SOC_IF_ERROR_RETURN
   2243             (READ_PHY54682_1000X_MII_ANAr(unit, pc, &mii_adv));
   2244 
   2245         if (mii_adv & MII_ANA_C37_FD) {
   2246             ability->speed_full_duplex |= SOC_PA_SPEED_1000MB;
   2247         }
   2248         if (mii_adv & MII_ANA_C37_HD) {
   2249             ability->speed_half_duplex |= SOC_PA_SPEED_1000MB;
   2250         }
   2251         switch (mii_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) {
   2252         case MII_ANA_C37_PAUSE:
   2253             ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   2254             break;
   2255         case MII_ANA_C37_ASYM_PAUSE:
   2256             ability->pause = SOC_PA_PAUSE_TX;
   2257             break;
   2258         case (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE):
   2259             ability->pause = SOC_PA_PAUSE_RX;
   2260             break;
   2261         }
   2262     }
   2263     return SOC_E_NONE;
   2264 }
   2265 
   2266 /*
   2267  * Function:
   2268  *      phy_54682_ability_remote_get
   2269  * Purpose:
   2270  *      Get partners current advertisement for auto-negotiation.
   2271  * Parameters:
   2272  *      unit    - StrataSwitch unit #.
   2273  *      port    - StrataSwitch port #.
   2274  *      ability - Port ability indicating supported options/speeds.
   2275  * Returns:
   2276  *      SOC_E_XXX
   2277  * Notes:
   2278  *      The remote advertisement is retrieved for the ACTIVE medium.
   2279  *      No synchronization performed at this level. If Autonegotiation is
   2280  *      disabled or in progress, this routine will return an error.
   2281  */
   2282 
   2283 STATIC int
   2284 phy_54682_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2285 {
   2286     phy_ctrl_t       *pc;
   2287     uint16            mii_stat;
   2288     uint16            mii_anp;
   2289     uint16            mii_gb_stat;
   2290     uint16            eee_resolution;
   2291     uint16            data;
   2292 
   2293     if (NULL == ability) {
   2294         return (SOC_E_PARAM);
   2295     }
   2296 
   2297     pc = EXT_PHY_SW_STATE(unit, port);
   2298     if (PHY_COPPER_MODE(unit, port)) {
   2299         SOC_IF_ERROR_RETURN
   2300             (READ_PHY54682_MII_STATr(unit, pc, &mii_stat));
   2301 
   2302         sal_memset(ability, 0, sizeof(*ability));
   2303 
   2304         if ((mii_stat & MII_STAT_AN_DONE & MII_STAT_LA)
   2305                    == (MII_STAT_AN_DONE & MII_STAT_LA)) {
   2306             /* Decode remote advertisement only when link is up and autoneg is
   2307              * completed.
   2308              */
   2309             SOC_IF_ERROR_RETURN
   2310                 (READ_PHY54682_MII_ANPr(unit, pc, &mii_anp));
   2311             SOC_IF_ERROR_RETURN
   2312                 (READ_PHY54682_MII_GB_STATr(unit, pc, &mii_gb_stat));
   2313 
   2314             if (mii_anp & MII_ANA_HD_10) {
   2315                 ability->speed_half_duplex |= SOC_PA_SPEED_10MB;
   2316             }
   2317             if (mii_anp & MII_ANA_HD_100) {
   2318                 ability->speed_half_duplex |= SOC_PA_SPEED_100MB;
   2319             }
   2320             if (mii_anp & MII_ANA_FD_10) {
   2321                ability->speed_full_duplex |= SOC_PA_SPEED_10MB;
   2322             }
   2323             if (mii_anp & MII_ANA_FD_100) {
   2324                ability->speed_full_duplex |= SOC_PA_SPEED_100MB;
   2325             }
   2326 
   2327             switch (mii_anp & (MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE)) {
   2328             case MII_ANA_PAUSE:
   2329                 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   2330                 break;
   2331             case MII_ANA_ASYM_PAUSE:
   2332                 ability->pause = SOC_PA_PAUSE_TX;
   2333                 break;
   2334             case MII_ANA_PAUSE | MII_ANA_ASYM_PAUSE:
   2335                 ability->pause = SOC_PA_PAUSE_RX;
   2336                 break;
   2337            }
   2338 
   2339             /* GE Specific values */
   2340 
   2341             if (mii_gb_stat & MII_GB_STAT_LP_1000HD) {
   2342             ability->speed_half_duplex |= SOC_PA_SPEED_1000MB;
   2343             }
   2344             if (mii_gb_stat & MII_GB_STAT_LP_1000FD) {
   2345                 ability->speed_full_duplex |= SOC_PA_SPEED_1000MB;
   2346             }
   2347             /* EEE settings */
   2348             if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2349                 SOC_IF_ERROR_RETURN
   2350                 (READ_PHY54682_EEE_RESOLUTION_STATr(unit, pc, &eee_resolution));
   2351                 if (eee_resolution & 0x04) {
   2352                     ability->eee |= SOC_PA_EEE_1GB_BASET;
   2353                 }
   2354                 if (eee_resolution & 0x02) {
   2355                     ability->eee |= SOC_PA_EEE_100MB_BASETX;
   2356                 }
   2357             }
   2358 
   2359         } else {
   2360             /* Simply return local abilities */
   2361             phy_54682_ability_advert_get(unit, port, ability);
   2362         }
   2363     } else {    /* PHY_FIBER_MODE */
   2364 
   2365         /* read the 1000BASE-X     Control Reg ( Address 0x00 ),
   2366          *   Auto-Neg Link Partner Ability Reg ( Address 0x05 )
   2367          */
   2368         SOC_IF_ERROR_RETURN
   2369             (READ_PHY54682_1000X_MII_CTRLr(unit, pc, &data));
   2370         if (!(data & MII_CTRL_AE)) {
   2371             return SOC_E_DISABLED;
   2372         }
   2373 
   2374         SOC_IF_ERROR_RETURN
   2375             (READ_PHY54682_1000X_MII_ANPr(unit, pc, &data));
   2376 
   2377         if (data & MII_ANP_SGMII_MODE) {
   2378             /* Unable to determine remote link partner's advertisement */ 
   2379             return SOC_E_NONE;
   2380         }
   2381 
   2382         if (data & MII_ANP_C37_FD) {
   2383             ability->speed_full_duplex |= SOC_PA_SPEED_1000MB;
   2384         }
   2385         if (data & MII_ANP_C37_HD) {
   2386             ability->speed_half_duplex |= SOC_PA_SPEED_1000MB;
   2387         }
   2388         switch (data & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
   2389         case MII_ANP_C37_PAUSE:
   2390             ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
   2391             break;
   2392         case MII_ANP_C37_ASYM_PAUSE:
   2393             ability->pause = SOC_PA_PAUSE_TX;
   2394             break;
   2395         case (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE):
   2396             ability->pause = SOC_PA_PAUSE_RX;
   2397             break;
   2398         }
   2399     }
   2400     LOG_INFO(BSL_LS_SOC_PHY,
   2401              (BSL_META_U(unit,
   2402                          "phy_54682_ability_remote_get:unit=%d p=%d pause=%08x sp=%08x\n"),
   2403               unit, port, ability->pause, ability->speed_full_duplex));
   2404 
   2405     return SOC_E_NONE;
   2406 }
   2407 
   2408 /*
   2409  * Function:
   2410  *      phy_54682_ability_local_get
   2411  * Purpose:
   2412  *      Get the device's complete abilities.
   2413  * Parameters:
   2414  *      unit - StrataSwitch unit #.
   2415  *      port - StrataSwitch port #.
   2416  *      ability - return device's abilities.
   2417  * Returns:
   2418  *      SOC_E_XXX
   2419  */
   2420 STATIC int
   2421 _phy_54682_ability_cu_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2422 {
   2423     phy_ctrl_t *pc;
   2424 
   2425     pc = EXT_PHY_SW_STATE(unit, port);
   2426 
   2427 
   2428     if (NULL == ability) {
   2429         return SOC_E_PARAM;
   2430     }
   2431 
   2432     ability->speed_half_duplex  = SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB;
   2433     ability->speed_full_duplex  = SOC_PA_SPEED_1000MB |SOC_PA_SPEED_100MB | 
   2434                                   SOC_PA_SPEED_10MB;
   2435                                   
   2436     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   2437     ability->interface = SOC_PA_INTF_SGMII;
   2438     ability->medium    = SOC_PA_MEDIUM_COPPER; 
   2439     ability->loopback  = SOC_PA_LB_PHY;
   2440     ability->flags     = SOC_PA_AUTONEG;
   2441     
   2442     /* EEE settings */
   2443     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   2444             ability->eee |= SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX;
   2445     }
   2446 
   2447     if (pc->automedium) {
   2448         ability->flags     |= SOC_PA_COMBO;
   2449     }
   2450     return SOC_E_NONE;
   2451 }
   2452 
   2453 STATIC int
   2454 _phy_54682_ability_fiber_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2455 {
   2456     phy_ctrl_t *pc;
   2457 
   2458     pc = EXT_PHY_SW_STATE(unit, port);
   2459 
   2460     if (NULL == ability) {
   2461         return SOC_E_PARAM;
   2462     }
   2463 
   2464     ability->speed_half_duplex  = SOC_PA_SPEED_100MB;
   2465     ability->speed_full_duplex  = SOC_PA_SPEED_1000MB |SOC_PA_SPEED_100MB;
   2466                                   
   2467     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM;
   2468     ability->interface = SOC_PA_INTF_SGMII;
   2469     ability->medium    = SOC_PA_MEDIUM_FIBER; 
   2470     ability->loopback  = SOC_PA_LB_PHY;
   2471     ability->flags     = SOC_PA_AUTONEG;
   2472 
   2473     if (pc->automedium) {
   2474         ability->flags     |= SOC_PA_COMBO;
   2475     }
   2476     return SOC_E_NONE;
   2477 }
   2478 
   2479 
   2480 STATIC int
   2481 phy_54682_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
   2482 {
   2483     if (PHY_COPPER_MODE(unit, port)) {
   2484         SOC_IF_ERROR_RETURN
   2485             (_phy_54682_ability_cu_local_get(unit, port, ability));
   2486     } else {
   2487         SOC_IF_ERROR_RETURN
   2488             (_phy_54682_ability_fiber_local_get(unit, port, ability));
   2489     }
   2490     return SOC_E_NONE;
   2491 }
   2492 
   2493 /*
   2494  * Function:
   2495  *      phy_54682_lb_set
   2496  * Purpose:
   2497  *      Set the local PHY loopback mode.
   2498  * Parameters:
   2499  *      unit - StrataSwitch unit #.
   2500  *      port - StrataSwitch port #.
   2501  *      loopback - Boolean: true = enable loopback, false = disable.
   2502  * Returns:
   2503  *      SOC_E_XXX
   2504  * Notes:
   2505  *      The loopback mode is set only for the ACTIVE medium.
   2506  *      No synchronization performed at this level.
   2507  */
   2508 
   2509 STATIC int
   2510 phy_54682_lb_set(int unit, soc_port_t port, int enable)
   2511 {
   2512     int            rv;
   2513     uint16         data;
   2514     phy_ctrl_t    *pc;
   2515 
   2516     pc = EXT_PHY_SW_STATE(unit, port);
   2517     rv = SOC_E_NONE;
   2518 
   2519 #if AUTO_MDIX_WHEN_AN_DIS
   2520     {
   2521         /* Disable Auto-MDIX When autoneg disabled */
   2522         /* Enable Auto-MDIX When autoneg disabled */
   2523         data = (enable) ? 0x0000 : 0x0200;
   2524         SOC_IF_ERROR_RETURN
   2525             (MODIFY_PHY_54682_MII_MISC_CTRLr(unit, pc, data, 0x0200)); 
   2526     }
   2527 #endif
   2528 
   2529     if (PHY_COPPER_MODE(unit, port)) {
   2530         rv = phy_fe_ge_lb_set(unit, port, enable);
   2531 
   2532     } else { 
   2533         data = (enable) ? MII_CTRL_LE : 0;
   2534         rv   = MODIFY_PHY54682_1000X_MII_CTRLr(unit, pc, data, MII_CTRL_LE);
   2535         if (enable && SOC_SUCCESS(rv)) {
   2536             uint16        stat;
   2537             int           link;
   2538             soc_timeout_t to;
   2539 
   2540             /* Wait up to 5000 msec for link up */
   2541             soc_timeout_init(&to, 5000000, 0);
   2542             link = 0;
   2543             while (!soc_timeout_check(&to)) {
   2544                 rv = READ_PHY54682_1000X_MII_STATr(unit, pc, &stat);
   2545                 link = stat & MII_STAT_LA;
   2546                 if (link || SOC_FAILURE(rv)) {
   2547                     break;
   2548                 }
   2549             }
   2550             if (!link) {
   2551                 LOG_WARN(BSL_LS_SOC_PHY,
   2552                          (BSL_META_U(unit,
   2553                                      "phy_54682_lb_set: u=%d p=%d TIMEOUT\n"),
   2554                           unit, port));
   2555 
   2556                 rv = SOC_E_TIMEOUT;
   2557             }
   2558         }
   2559     }
   2560     LOG_INFO(BSL_LS_SOC_PHY,
   2561              (BSL_META_U(unit,
   2562                          "phy_54682_lb_set: u=%d p=%d en=%d rv=%d\n"), 
   2563               unit, port, enable, rv));
   2564 
   2565     return rv; 
   2566 }
   2567 
   2568 /*
   2569  * Function:
   2570  *      phy_54682_lb_get
   2571  * Purpose:
   2572  *      Get the local PHY loopback mode.
   2573  * Parameters:
   2574  *      unit - StrataSwitch unit #.
   2575  *      port - StrataSwitch port #.
   2576  *      loopback - (OUT) Boolean: true = enable loopback, false = disable.
   2577  * Returns:
   2578  *      SOC_E_XXX
   2579  * Notes:
   2580  *      The loopback mode is retrieved for the ACTIVE medium.
   2581  */
   2582 
   2583 STATIC int
   2584 phy_54682_lb_get(int unit, soc_port_t port, int *enable)
   2585 {
   2586     uint16               data;
   2587     phy_ctrl_t    *pc;
   2588 
   2589     pc = EXT_PHY_SW_STATE(unit, port);
   2590 
   2591     if (PHY_COPPER_MODE(unit, port)) {
   2592         SOC_IF_ERROR_RETURN
   2593             (phy_fe_ge_lb_get(unit, port, enable));
   2594     } else {
   2595        SOC_IF_ERROR_RETURN
   2596            (READ_PHY54682_1000X_MII_CTRLr(unit, pc, &data));
   2597         *enable = (data & MII_CTRL_LE) ? 1 : 0;
   2598     }
   2599 
   2600     return SOC_E_NONE; 
   2601 }
   2602 
   2603 /*
   2604  * Function:
   2605  *      phy_54682_interface_set
   2606  * Purpose:
   2607  *      Set the current operating mode of the PHY.
   2608  * Parameters:
   2609  *      unit - StrataSwitch unit #.
   2610  *      port - StrataSwitch port #.
   2611  *      pif - one of SOC_PORT_IF_*
   2612  * Returns:
   2613  *      SOC_E_NONE - success
   2614  *      SOC_E_UNAVAIL - unsupported interface
   2615  */
   2616 
   2617 STATIC int
   2618 phy_54682_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   2619 {
   2620     COMPILER_REFERENCE(unit);
   2621     COMPILER_REFERENCE(port);
   2622 
   2623     switch (pif) {
   2624     case SOC_PORT_IF_SGMII:
   2625     case SOC_PORT_IF_GMII:
   2626         return SOC_E_NONE;
   2627     default:
   2628         return SOC_E_UNAVAIL;
   2629     }
   2630 }
   2631 
   2632 /*
   2633  * Function:
   2634  *      phy_54682_interface_get
   2635  * Purpose:
   2636  *      Get the current operating mode of the PHY.
   2637  * Parameters:
   2638  *      unit - StrataSwitch unit #.
   2639  *      port - StrataSwitch port #.
   2640  *      pif - (OUT) one of SOC_PORT_IF_*
   2641  * Returns:
   2642  *      SOC_E_NONE
   2643  */
   2644 
   2645 STATIC int
   2646 phy_54682_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   2647 {
   2648     COMPILER_REFERENCE(unit);
   2649     COMPILER_REFERENCE(port);
   2650 
   2651     *pif = SOC_PORT_IF_SGMII;
   2652 
   2653     return SOC_E_NONE;
   2654 }
   2655 
   2656 /*
   2657  * Function:
   2658  *      phy_54682_mdix_set
   2659  * Description:
   2660  *      Set the Auto-MDIX mode of a port/PHY
   2661  * Parameters:
   2662  *      unit - Device number
   2663  *      port - Port number
   2664  *      mode - One of:
   2665  *              SOC_PORT_MDIX_AUTO
   2666  *                      Enable auto-MDIX when autonegotiation is enabled
   2667  *              SOC_PORT_MDIX_FORCE_AUTO
   2668  *                      Enable auto-MDIX always
   2669  *              SOC_PORT_MDIX_NORMAL
   2670  *                      Disable auto-MDIX
   2671  *              SOC_PORT_MDIX_XOVER
   2672  *                      Disable auto-MDIX, and swap cable pairs
   2673  * Return Value:
   2674  *      SOC_E_XXX
   2675  */
   2676 STATIC int
   2677 phy_54682_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode)
   2678 {
   2679     phy_ctrl_t    *pc;
   2680     int                  speed;
   2681 
   2682     pc = EXT_PHY_SW_STATE(unit, port);
   2683     if (PHY_COPPER_MODE(unit, port)) {
   2684         switch (mode) {
   2685         case SOC_PORT_MDIX_AUTO:
   2686             /* Clear bit 14 for automatic MDI crossover */
   2687             SOC_IF_ERROR_RETURN
   2688                 (MODIFY_PHY54682_MII_ECRr(unit, pc, 0, 0x4000));
   2689 
   2690             /* Clear bit 9 to disable forced auto MDI xover */
   2691             SOC_IF_ERROR_RETURN
   2692                 (MODIFY_PHY54682_MII_MISC_CTRLr(unit, pc, 0, 0x0200));
   2693             break;
   2694 
   2695         case SOC_PORT_MDIX_FORCE_AUTO:
   2696             /* Clear bit 14 for automatic MDI crossover */
   2697             SOC_IF_ERROR_RETURN
   2698                 (MODIFY_PHY54682_MII_ECRr(unit, pc, 0, 0x4000));
   2699 
   2700             /* Set bit 9 to disable forced auto MDI xover */
   2701             SOC_IF_ERROR_RETURN
   2702                 (MODIFY_PHY54682_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200));
   2703             break;
   2704 
   2705         case SOC_PORT_MDIX_NORMAL:
   2706             SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed));
   2707             if (speed == 0 || speed == 10 || speed == 100) {
   2708                 /* Set bit 14 for automatic MDI crossover */
   2709                 SOC_IF_ERROR_RETURN
   2710                     (MODIFY_PHY54682_MII_ECRr(unit, pc, 0x4000, 0x4000));
   2711 
   2712                 SOC_IF_ERROR_RETURN
   2713                     (WRITE_PHY54682_TEST1r(unit, pc, 0));
   2714             } else {
   2715                 return SOC_E_UNAVAIL;
   2716             }
   2717             break;
   2718 
   2719         case SOC_PORT_MDIX_XOVER:
   2720             SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed));
   2721             if (speed == 0 || speed == 10 || speed == 100) {
   2722                 /* Set bit 14 for automatic MDI crossover */
   2723                 SOC_IF_ERROR_RETURN
   2724                     (MODIFY_PHY54682_MII_ECRr(unit, pc, 0x4000, 0x4000));
   2725 
   2726                 SOC_IF_ERROR_RETURN
   2727                     (WRITE_PHY54682_TEST1r(unit, pc, 0x0080));
   2728             } else {
   2729                 return SOC_E_UNAVAIL;
   2730             }
   2731             break;
   2732 
   2733         default:
   2734             return SOC_E_PARAM;
   2735         }
   2736         pc->copper.mdix = mode;
   2737     } else {    /* fiber */
   2738         if (mode != SOC_PORT_MDIX_NORMAL) {
   2739             return SOC_E_UNAVAIL;
   2740         }
   2741     }
   2742     return SOC_E_NONE;
   2743 }        
   2744 
   2745 #if defined(BCM_WARM_BOOT_SUPPORT)
   2746 /*
   2747  * Function:
   2748  *      _phy_54682_mdix_wb_update
   2749  * Description:
   2750  *      Read the hw, derive the mode and update the mdix mode in sw structure
   2751  *      during wb.
   2752  * Parameters:
   2753  *      unit - (IN) Device number
   2754  *      port - (IN) Port number
   2755  *      mode - (OUT) :One of:
   2756  *              SOC_PORT_MDIX_AUTO
   2757  *                      Enable auto-MDIX when autonegotiation is enabled
   2758  *              SOC_PORT_MDIX_FORCE_AUTO
   2759  *                      Enable auto-MDIX always
   2760  *              SOC_PORT_MDIX_NORMAL
   2761  *                      Disable auto-MDIX
   2762  *              SOC_PORT_MDIX_XOVER
   2763  *                      Disable auto-MDIX, and swap cable pairs
   2764  * Return Value:
   2765  *      SOC_E_XXX
   2766  */
   2767 STATIC int
   2768 _phy_54682_mdix_wb_update(int unit, soc_port_t port)
   2769 {
   2770     phy_ctrl_t    *pc;
   2771     int            speed;
   2772     int            mode = 0;
   2773     uint16         val = 0;
   2774 
   2775     pc = EXT_PHY_SW_STATE(unit, port);
   2776 
   2777     /* Check bit 14 for automatic MDI crossover */
   2778     SOC_IF_ERROR_RETURN (READ_PHY54682_MII_ECRr(unit, pc, &val));
   2779     if(val & 0x4000) {
   2780         SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed));
   2781         if (speed == 0 || speed == 10 || speed == 100) {
   2782             SOC_IF_ERROR_RETURN (READ_PHY54682_TEST1r(unit, pc, &val));
   2783             if (0 == val) {
   2784                 mode = SOC_PORT_MDIX_NORMAL;
   2785             } else if (0x80 == val) {
   2786                 mode = SOC_PORT_MDIX_XOVER;
   2787             } else {
   2788                 return SOC_E_UNAVAIL;
   2789             }
   2790         } else {
   2791             return SOC_E_UNAVAIL;
   2792         }
   2793     } else {
   2794         /* Check bit 9 forced auto MDI xover */
   2795         SOC_IF_ERROR_RETURN (READ_PHY54682_MII_MISC_CTRLr(unit, pc,&val));
   2796         if (val & 0x200) {
   2797             /* bit 9 Set, forced auto MDI xover */
   2798             mode = SOC_PORT_MDIX_FORCE_AUTO;
   2799         } else {
   2800             /* bit 9 Clear, forced auto MDI xover */
   2801             mode = SOC_PORT_MDIX_AUTO;
   2802         }
   2803     }
   2804     pc->copper.mdix = mode;
   2805 
   2806     return SOC_E_NONE;
   2807 }
   2808 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */
   2809 
   2810 /*
   2811  * Function:
   2812  *      phy_54682_mdix_get
   2813  * Description:
   2814  *      Get the Auto-MDIX mode of a port/PHY
   2815  * Parameters:
   2816  *      unit - Device number
   2817  *      port - Port number
   2818  *      mode - (Out) One of:
   2819  *              SOC_PORT_MDIX_AUTO
   2820  *                      Enable auto-MDIX when autonegotiation is enabled
   2821  *              SOC_PORT_MDIX_FORCE_AUTO
   2822  *                      Enable auto-MDIX always
   2823  *              SOC_PORT_MDIX_NORMAL
   2824  *                      Disable auto-MDIX
   2825  *              SOC_PORT_MDIX_XOVER
   2826  *                      Disable auto-MDIX, and swap cable pairs
   2827  * Return Value:
   2828  *      SOC_E_XXX
   2829  */
   2830 STATIC int
   2831 phy_54682_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode)
   2832 {
   2833     phy_ctrl_t    *pc;
   2834     int            speed;
   2835 
   2836     if (mode == NULL) {
   2837         return SOC_E_PARAM;
   2838     }
   2839 
   2840 #if defined(BCM_WARM_BOOT_SUPPORT)
   2841     if (SOC_WARM_BOOT(unit)) {
   2842         return _phy_54682_mdix_wb_update(unit, port);
   2843     }
   2844 #endif /* defined(BCM_WARM_BOOT_SUPPORT) */
   2845 
   2846     pc = EXT_PHY_SW_STATE(unit, port);
   2847 
   2848     if (PHY_COPPER_MODE(unit, port)) {
   2849         SOC_IF_ERROR_RETURN(phy_54682_speed_get(unit, port, &speed));
   2850         if (speed == 1000) {
   2851            *mode = SOC_PORT_MDIX_AUTO;
   2852         } else {
   2853             *mode = pc->copper.mdix;
   2854         }
   2855     } else {
   2856         *mode = SOC_PORT_MDIX_NORMAL;
   2857     }
   2858 
   2859     return SOC_E_NONE;
   2860 }    
   2861 
   2862 /*
   2863  * Function:
   2864  *      phy_54682_mdix_status_get
   2865  * Description:
   2866  *      Get the current MDIX status on a port/PHY
   2867  * Parameters:
   2868  *      unit    - Device number
   2869  *      port    - Port number
   2870  *      status  - (OUT) One of:
   2871  *              SOC_PORT_MDIX_STATUS_NORMAL
   2872  *                      Straight connection
   2873  *              SOC_PORT_MDIX_STATUS_XOVER
   2874  *                      Crossover has been performed
   2875  * Return Value:
   2876  *      SOC_E_XXX
   2877  */
   2878 STATIC int
   2879 phy_54682_mdix_status_get(int unit, soc_port_t port, 
   2880                          soc_port_mdix_status_t *status)
   2881 {
   2882     phy_ctrl_t    *pc;
   2883     uint16          data;
   2884 
   2885     if (status == NULL) {
   2886         return SOC_E_PARAM;
   2887     }
   2888 
   2889     pc = EXT_PHY_SW_STATE(unit, port);
   2890 
   2891     if (PHY_COPPER_MODE(unit, port)) {
   2892         SOC_IF_ERROR_RETURN
   2893             (READ_PHY54682_MII_ESRr(unit, pc, &data));
   2894         if (data & 0x2000) {
   2895             *status = SOC_PORT_MDIX_STATUS_XOVER;
   2896         } else {
   2897             *status = SOC_PORT_MDIX_STATUS_NORMAL;
   2898         }
   2899     } else {
   2900         *status = SOC_PORT_MDIX_STATUS_NORMAL;
   2901     }
   2902 
   2903     return SOC_E_NONE;
   2904 }    
   2905 
   2906 STATIC int
   2907 _phy_54682_power_mode_set (int unit, soc_port_t port, int mode)
   2908 {
   2909     phy_ctrl_t    *pc;
   2910 
   2911     pc       = EXT_PHY_SW_STATE(unit, port);
   2912 
   2913     if (pc->power_mode == mode) {
   2914         return SOC_E_NONE;
   2915     }
   2916 
   2917     if ((mode == SOC_PHY_CONTROL_POWER_LOW) || (mode == SOC_PHY_CONTROL_POWER_AUTO_LOW)) {
   2918         /* enable dsp clock */
   2919         SOC_IF_ERROR_RETURN
   2920             (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00));
   2921 
   2922         /* enable low power 136 */
   2923         SOC_IF_ERROR_RETURN
   2924             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,0x80,0x80));
   2925 
   2926         /* reduce tx bias current to -20% */
   2927         SOC_IF_ERROR_RETURN
   2928             (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75));
   2929         SOC_IF_ERROR_RETURN
   2930             (WRITE_PHY_REG(unit, pc, 0x15, 0x1555));
   2931 
   2932         /* disable dsp clock */
   2933         SOC_IF_ERROR_RETURN
   2934             (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00));
   2935 
   2936         /* set the auto power down setting */
   2937         SOC_IF_ERROR_RETURN
   2938             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,
   2939                         (mode == SOC_PHY_CONTROL_POWER_AUTO_LOW) ? PHY_54682_AUTO_PWRDWN_EN : 0,
   2940                         PHY_54682_AUTO_PWRDWN_EN));
   2941         pc->power_mode = mode;
   2942 
   2943     } else if ((mode == SOC_PHY_CONTROL_POWER_FULL) || (mode == SOC_PHY_CONTROL_POWER_AUTO_FULL)) {
   2944 
   2945         /* back to normal mode */
   2946         /* enable dsp clock */
   2947         SOC_IF_ERROR_RETURN
   2948             (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0c00,0x0c00));
   2949 
   2950         /* disable low power 136 */
   2951         SOC_IF_ERROR_RETURN
   2952             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,0x00,0x80));
   2953 
   2954         /* set tx bias current to nominal */
   2955         SOC_IF_ERROR_RETURN
   2956             (WRITE_PHY_REG(unit, pc, 0x17, 0x0f75));
   2957         SOC_IF_ERROR_RETURN
   2958             (WRITE_PHY_REG(unit, pc, 0x15, 0x0));
   2959 
   2960         /* disable dsp clock */
   2961         SOC_IF_ERROR_RETURN
   2962             (MODIFY_PHY54682_MII_AUX_CTRLr(unit,pc,0x0400,0x0c00));
   2963 
   2964         /* set the auto power down setting */
   2965         SOC_IF_ERROR_RETURN
   2966             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,
   2967                         (mode == SOC_PHY_CONTROL_POWER_AUTO_FULL) ? PHY_54682_AUTO_PWRDWN_EN : 0,
   2968                         PHY_54682_AUTO_PWRDWN_EN));
   2969         pc->power_mode = mode;
   2970     } else if (mode == SOC_PHY_CONTROL_POWER_AUTO) {
   2971         SOC_IF_ERROR_RETURN
   2972             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,
   2973                         PHY_54682_AUTO_PWRDWN_EN,
   2974                         PHY_54682_AUTO_PWRDWN_EN));
   2975         pc->power_mode = mode;
   2976     } else if (mode == SOC_PHY_CONTROL_POWER_AUTO_DISABLE) {
   2977         SOC_IF_ERROR_RETURN
   2978             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,
   2979                         0,
   2980                         PHY_54682_AUTO_PWRDWN_EN));
   2981         pc->power_mode = mode;
   2982     }
   2983     return SOC_E_NONE;
   2984 }
   2985 
   2986 /*
   2987  * Function:
   2988  *      _phy_54682_eee_enable
   2989  * Purpose:
   2990  *      Enable or disable EEE (Native)
   2991  * Parameters:
   2992  *      unit   - StrataSwitch unit #.
   2993  *      port   - StrataSwitch port #.
   2994  *      enable - Enable Native EEE
   2995  * Returns:
   2996  *      SOC_E_NONE
   2997  */
   2998 STATIC int
   2999 _phy_54682_eee_enable(int unit, soc_port_t port, int enable)
   3000 {
   3001     phy_ctrl_t *pc;
   3002     
   3003     if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3004         return SOC_E_FAIL;
   3005     }
   3006     pc = EXT_PHY_SW_STATE(unit, port);
   3007 
   3008     if (enable == 1) {
   3009         if (PHY_IS_BCM54685E_A0A1(pc)) {
   3010             SOC_IF_ERROR_RETURN
   3011                 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00));
   3012 
   3013             SOC_IF_ERROR_RETURN(
   3014                 WRITE_PHY_REG(unit, pc, 0x17, 0x0ffe));
   3015             SOC_IF_ERROR_RETURN(
   3016                 WRITE_PHY_REG(unit, pc, 0x15, 0x0100));
   3017 
   3018             SOC_IF_ERROR_RETURN(
   3019                 WRITE_PHY_REG(unit, pc, 0x17, 0x0fff));
   3020             SOC_IF_ERROR_RETURN(
   3021                 WRITE_PHY_REG(unit, pc, 0x15, 0x4000));
   3022 
   3023             SOC_IF_ERROR_RETURN(
   3024                 WRITE_PHY_REG(unit, pc, 0x17, 0x2022));
   3025             SOC_IF_ERROR_RETURN(
   3026                 WRITE_PHY_REG(unit, pc, 0x15, 0x01f1));
   3027 
   3028             SOC_IF_ERROR_RETURN(
   3029                 WRITE_PHY_REG(unit, pc, 0x17, 0x4021));
   3030             SOC_IF_ERROR_RETURN(
   3031                 WRITE_PHY_REG(unit, pc, 0x15, 0x0887));
   3032 
   3033             SOC_IF_ERROR_RETURN(
   3034                 WRITE_PHY_REG(unit, pc, 0x17, 0x2021));
   3035             SOC_IF_ERROR_RETURN(
   3036                 WRITE_PHY_REG(unit, pc, 0x15, 0x8983));
   3037 
   3038             SOC_IF_ERROR_RETURN(
   3039                 WRITE_PHY_REG(unit, pc, 0x17, 0x0021));
   3040             SOC_IF_ERROR_RETURN(
   3041                 WRITE_PHY_REG(unit, pc, 0x15, 0x4600));
   3042 
   3043             SOC_IF_ERROR_RETURN(
   3044                 WRITE_PHY_REG(unit, pc, 0x17, 0x0e40));
   3045             SOC_IF_ERROR_RETURN(
   3046                 WRITE_PHY_REG(unit, pc, 0x15, 0x0000));
   3047 
   3048             SOC_IF_ERROR_RETURN
   3049                 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00));
   3050 
   3051             SOC_IF_ERROR_RETURN
   3052                 (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0xc000, 0xc000));
   3053             SOC_IF_ERROR_RETURN
   3054                 (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0xf300, 0xf300));
   3055         } else {
   3056             SOC_IF_ERROR_RETURN
   3057                 (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0xc000, 0xc000)); /* 7.803d */
   3058         }
   3059         SOC_IF_ERROR_RETURN
   3060             (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0006, 0x0006));
   3061         pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   3062 
   3063         SOC_IF_ERROR_RETURN
   3064             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */
   3065 
   3066     } else {  /* enable != 1 */
   3067         if (PHY_IS_BCM54685E_A0A1(pc)) {
   3068             SOC_IF_ERROR_RETURN
   3069                 (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0x0000, 0xc000));
   3070             SOC_IF_ERROR_RETURN
   3071                 (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0x0000, 0xf300));
   3072         } else {
   3073             SOC_IF_ERROR_RETURN
   3074                 (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0x0000, 0xc000)); /* 7.803d */
   3075         }
   3076         SOC_IF_ERROR_RETURN
   3077             (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0000, 0x0006));
   3078         pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   3079 
   3080         SOC_IF_ERROR_RETURN
   3081             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x1)); /* exp af */
   3082     }
   3083 
   3084     return SOC_E_NONE;
   3085 }
   3086 
   3087 /*
   3088  * Function:
   3089  *      _phy_54682_eee_auto_enable
   3090  * Purpose:
   3091  *      Enable or disable EEE (Native)
   3092  * Parameters:
   3093  *      unit   - StrataSwitch unit #.
   3094  *      port   - StrataSwitch port #.
   3095  *      enable - Enable Native EEE
   3096  * Returns:
   3097  *      SOC_E_NONE
   3098  */
   3099 STATIC int
   3100 _phy_54682_eee_auto_enable(int unit, soc_port_t port, int enable)
   3101 {
   3102     phy_ctrl_t *pc;
   3103     
   3104     if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3105         return SOC_E_FAIL;
   3106     }
   3107     pc = EXT_PHY_SW_STATE(unit, port);
   3108 
   3109     if (enable == 1) {
   3110         if (PHY_IS_BCM54685E_A0A1(pc)) {
   3111             SOC_IF_ERROR_RETURN
   3112                     (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0c00, 0x0c00));
   3113 
   3114             SOC_IF_ERROR_RETURN(
   3115                     WRITE_PHY_REG(unit, pc, 0x17, 0x0ffe));
   3116             SOC_IF_ERROR_RETURN(
   3117                     WRITE_PHY_REG(unit, pc, 0x15, 0x0900));
   3118 
   3119             SOC_IF_ERROR_RETURN(
   3120                     WRITE_PHY_REG(unit, pc, 0x17, 0x0fff));
   3121             SOC_IF_ERROR_RETURN(
   3122                     WRITE_PHY_REG(unit, pc, 0x15, 0x4000));
   3123 
   3124             SOC_IF_ERROR_RETURN(
   3125                     WRITE_PHY_REG(unit, pc, 0x17, 0x2022));
   3126             SOC_IF_ERROR_RETURN(
   3127                     WRITE_PHY_REG(unit, pc, 0x15, 0x01f1));
   3128 
   3129             SOC_IF_ERROR_RETURN(
   3130                     WRITE_PHY_REG(unit, pc, 0x17, 0x2021));
   3131             SOC_IF_ERROR_RETURN(
   3132                     WRITE_PHY_REG(unit, pc, 0x15, 0x8983));
   3133 
   3134             SOC_IF_ERROR_RETURN(
   3135                     WRITE_PHY_REG(unit, pc, 0x17, 0x4021));
   3136             SOC_IF_ERROR_RETURN(
   3137                     WRITE_PHY_REG(unit, pc, 0x15, 0x0887));
   3138 
   3139             SOC_IF_ERROR_RETURN(
   3140                     WRITE_PHY_REG(unit, pc, 0x17, 0x0021));
   3141             SOC_IF_ERROR_RETURN(
   3142                     WRITE_PHY_REG(unit, pc, 0x15, 0x4600));
   3143 
   3144             SOC_IF_ERROR_RETURN(
   3145                     WRITE_PHY_REG(unit, pc, 0x17, 0x0fc0));
   3146             SOC_IF_ERROR_RETURN(
   3147                     WRITE_PHY_REG(unit, pc, 0x15, 0x0000));
   3148 
   3149             SOC_IF_ERROR_RETURN(
   3150                     WRITE_PHY_REG(unit, pc, 0x17, 0x0faf));
   3151             SOC_IF_ERROR_RETURN(
   3152                     WRITE_PHY_REG(unit, pc, 0x15, 0x0001));
   3153             /*
   3154             SOC_IF_ERROR_RETURN(
   3155                     WRITE_PHY_REG(unit, pc, 0x17, 0x0d07));
   3156             SOC_IF_ERROR_RETURN(
   3157                     WRITE_PHY_REG(unit, pc, 0x15, 0x0001));
   3158              */
   3159             SOC_IF_ERROR_RETURN
   3160                     (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0x0400, 0x0c00));
   3161 
   3162             SOC_IF_ERROR_RETURN
   3163                     (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0xc000, 0xc000));
   3164 
   3165             SOC_IF_ERROR_RETURN
   3166                     (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0xf300, 0x1300));
   3167 
   3168         } else {  /* ! PHY_IS_BCM54685E_A0A1 */
   3169             SOC_IF_ERROR_RETURN
   3170                     (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0xc000, 0xc000)); /* 7.803d */
   3171         }
   3172         SOC_IF_ERROR_RETURN
   3173             (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0006, 0x0006));
   3174         pc->copper.advert_ability.eee |= (SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   3175 
   3176         SOC_IF_ERROR_RETURN
   3177            (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7,
   3178                                                0x0001, 0x0003));
   3179         SOC_IF_ERROR_RETURN
   3180             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x1, 0x1)); /* exp af */
   3181 
   3182     } else {  /* enable != 1 */
   3183         SOC_IF_ERROR_RETURN
   3184             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 0x3)); /* exp af */
   3185         SOC_IF_ERROR_RETURN
   3186             (MODIFY_PHY54682_EEE_ADVr(unit, pc, 0x0000, 0x0006));
   3187         pc->copper.advert_ability.eee &= ~(SOC_PA_EEE_1GB_BASET | SOC_PA_EEE_100MB_BASETX);
   3188 
   3189         if (PHY_IS_BCM54685E_A0A1(pc)) {
   3190             SOC_IF_ERROR_RETURN
   3191                 (MODIFY_PHY54682_EEE_TEST_CTRL_Br(unit, pc, 0x0000, 0xc000)); /* 7.8031 */
   3192             SOC_IF_ERROR_RETURN
   3193                 (MODIFY_PHY54682_EEE_TEST_CTRL_Ar(unit, pc, 0x0000, 0xf300)); /* 7.8030 2 ops */
   3194         } else {
   3195             SOC_IF_ERROR_RETURN
   3196                 (MODIFY_PHY54682_EEE_803Dr(unit, pc, 0x0000, 0xc000)); /* 7.803d */
   3197         }
   3198     }
   3199 
   3200     return SOC_E_NONE;
   3201 }
   3202 
   3203 /*
   3204  * Function:
   3205  *      phy_54682_control_set
   3206  * Purpose:
   3207  *      Configure PHY device specific control fucntion.
   3208  * Parameters:
   3209  *      unit  - StrataSwitch unit #.
   3210  *      port  - StrataSwitch port #.
   3211  *      type  - Control to update
   3212  *      value - New setting for the control
   3213  * Returns:
   3214  *      SOC_E_NONE
   3215  */
   3216 STATIC int
   3217 phy_54682_control_set(int unit, soc_port_t port,
   3218                      soc_phy_control_t type, uint32 value)
   3219 {
   3220     int rv;
   3221     phy_ctrl_t *pc;
   3222     uint16 data, freq;
   3223     soc_port_t primary;
   3224     int offset, saved_autoneg;
   3225 
   3226     PHY_CONTROL_TYPE_CHECK(type);
   3227 
   3228     pc = EXT_PHY_SW_STATE(unit, port);
   3229     rv = SOC_E_NONE;
   3230     switch(type) {
   3231         case SOC_PHY_CONTROL_PREEMPHASIS:
   3232             /* fall through */
   3233         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   3234             rv = _phy_54682_tx_control_set(unit, port, type, value);
   3235             break;
   3236 
   3237         case SOC_PHY_CONTROL_POWER:
   3238             rv = _phy_54682_power_mode_set(unit,port,value);
   3239         break;
   3240 
   3241     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   3242         if (value <= PHY_54682_AUTO_PWRDWN_WAKEUP_MAX) {
   3243 
   3244             /* at least one unit */
   3245             if (value < PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT) {
   3246                 value = PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT;
   3247             }
   3248         } else { /* anything more then max, set to the max */
   3249             value = PHY_54682_AUTO_PWRDWN_WAKEUP_MAX;
   3250         }
   3251         SOC_IF_ERROR_RETURN
   3252             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,
   3253                       value/PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT,
   3254                       PHY_54682_AUTO_PWRDWN_WAKEUP_MASK));
   3255         break;
   3256 
   3257     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   3258         /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */
   3259         if (value < PHY_54682_AUTO_PWRDWN_SLEEP_MAX) {
   3260             data = 0; /* anything less than 5.4s, default to 2.7s */
   3261         } else {
   3262             data = PHY_54682_AUTO_PWRDWN_SLEEP_MASK;
   3263         }
   3264         SOC_IF_ERROR_RETURN
   3265             (MODIFY_PHY54682_AUTO_POWER_DOWNr(unit,pc,
   3266                       data,
   3267                       PHY_54682_AUTO_PWRDWN_SLEEP_MASK));
   3268         break;
   3269 
   3270 
   3271     case SOC_PHY_CONTROL_PORT_PRIMARY:
   3272             SOC_IF_ERROR_RETURN
   3273                 (soc_phyctrl_primary_set(unit, port, (soc_port_t)value));
   3274             break;
   3275 
   3276     case SOC_PHY_CONTROL_PORT_OFFSET:
   3277             SOC_IF_ERROR_RETURN
   3278                (soc_phyctrl_offset_set(unit, port, (int)value));
   3279         break;
   3280 
   3281     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   3282         SOC_IF_ERROR_RETURN
   3283             (soc_phyctrl_primary_get(unit, port, &primary));
   3284         SOC_IF_ERROR_RETURN
   3285             (soc_phyctrl_offset_get(unit, port, &offset));
   3286         SOC_IF_ERROR_RETURN
   3287             (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data));
   3288         if ( value ) {
   3289             SOC_IF_ERROR_RETURN
   3290                 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0,
   3291                      ( data & 0xf0 ) | ( offset & 0x7 )));
   3292         } else {
   3293             SOC_IF_ERROR_RETURN
   3294                 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0,
   3295                      ( data & 0xf0 ) | 0x8 ));
   3296         }
   3297         break;
   3298 
   3299     case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE:
   3300         SOC_IF_ERROR_RETURN
   3301             (soc_phyctrl_primary_get(unit, port, &primary));
   3302         SOC_IF_ERROR_RETURN
   3303             (soc_phyctrl_offset_get(unit, port, &offset));
   3304         SOC_IF_ERROR_RETURN
   3305             (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data));
   3306         if ( value ) {
   3307             SOC_IF_ERROR_RETURN
   3308                 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0,
   3309                      ( data & 0x0f ) | (( offset & 0x7 )<<4 )));
   3310         } else {
   3311             SOC_IF_ERROR_RETURN
   3312                 (phy_54682_toplvl_reg_write(unit, port, primary, 0x0,
   3313                      ( data & 0x0f ) | (0x8<<4) ));
   3314         }
   3315         break;
   3316 
   3317     case SOC_PHY_CONTROL_CLOCK_FREQUENCY:
   3318         switch (value) {
   3319         case 125000:
   3320             freq = 0x0;
   3321             break;
   3322         case 156250:
   3323             freq = 0x1;
   3324             break;
   3325         default:
   3326             return SOC_E_CONFIG;
   3327             break;
   3328         }
   3329         do {
   3330             pc->phy_id =  PHY54682_SLICE_ADDR(pc, 1);
   3331             SOC_IF_ERROR_BREAK
   3332                 (MODIFY_PHY54682_EXP_SERDES_MULTIPLIER_CTRLr(unit, pc, (freq << 9),
   3333                     (0x1 << 9)), rv);
   3334             pc->phy_id =  PHY54682_SLICE_ADDR(pc, 5);
   3335             SOC_IF_ERROR_BREAK
   3336                 (MODIFY_PHY54682_EXP_SERDES_MULTIPLIER_CTRLr(unit, pc, (freq << 9),
   3337                     (0x1 << 9)), rv);
   3338         } while(0);
   3339         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   3340         break;
   3341 
   3342     case SOC_PHY_CONTROL_EEE:
   3343         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3344             rv = SOC_E_UNAVAIL;
   3345         }
   3346 
   3347         if (value == 1) {
   3348             /* Enable Native EEE */
   3349             SOC_IF_ERROR_RETURN
   3350                 (_phy_54682_eee_enable(unit, port, 1));
   3351             saved_autoneg = pc->copper.autoneg_enable;
   3352             /* Initiate AN */
   3353             SOC_IF_ERROR_RETURN
   3354                 (phy_54682_autoneg_set(unit, port, 1));
   3355             pc->copper.autoneg_enable = saved_autoneg;
   3356             PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   3357             PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_MODE);
   3358         } else {
   3359             SOC_IF_ERROR_RETURN
   3360                 (_phy_54682_eee_enable(unit, port, 0));
   3361             /* Initiate AN if administratively enabled */
   3362             SOC_IF_ERROR_RETURN
   3363                 (phy_54682_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0));
   3364             PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   3365         }
   3366         break;
   3367 
   3368     case SOC_PHY_CONTROL_EEE_AUTO:
   3369         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3370             rv = SOC_E_UNAVAIL;
   3371         }
   3372 
   3373         if (value == 1) {
   3374             /* Disable Native EEE */
   3375             SOC_IF_ERROR_RETURN
   3376                 (_phy_54682_eee_enable(unit, port, 0));
   3377             /* Enable Auto EEE */
   3378             SOC_IF_ERROR_RETURN
   3379                 (_phy_54682_eee_auto_enable(unit, port, 1));
   3380             saved_autoneg = pc->copper.autoneg_enable;
   3381             /* Initiate AN */
   3382             SOC_IF_ERROR_RETURN
   3383                 (phy_54682_autoneg_set(unit, port, 1));
   3384             pc->copper.autoneg_enable = saved_autoneg;
   3385             PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   3386             PHY_FLAGS_SET(unit, pc->port, PHY_FLAGS_EEE_MODE);
   3387         } else {
   3388             /* Disable Auto EEE */
   3389             SOC_IF_ERROR_RETURN
   3390                 (_phy_54682_eee_auto_enable(unit, port, 0));
   3391             /* Initiate AN if administratively enabled */
   3392             SOC_IF_ERROR_RETURN
   3393                 (phy_54682_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0));
   3394             PHY_FLAGS_CLR(unit, pc->port, PHY_FLAGS_EEE_ENABLED);
   3395         }
   3396         break;
   3397 
   3398     case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD:
   3399         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3400             rv = SOC_E_UNAVAIL;
   3401         }
   3402 
   3403         if (value > 7) { /* Values needs to between 0 to 7 (inclusive) */
   3404             rv = SOC_E_CONFIG;
   3405         }
   3406 
   3407         SOC_IF_ERROR_RETURN
   3408            (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7,
   3409                                                    value<<8, 0x0700));
   3410         /* Setting GPHY core, MII buffer register as well */
   3411         SOC_IF_ERROR_RETURN
   3412            (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 
   3413                                                     value<<8, 0x0700));
   3414         break;
   3415 
   3416 
   3417     case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY:
   3418         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3419             rv = SOC_E_UNAVAIL;
   3420         }
   3421         /* Fixed latency can have only 0 or 1 value  */
   3422         if ((value != FALSE) && (value != TRUE)) {
   3423             return SOC_E_PARAM;
   3424         }
   3425         if (value == FALSE) { 
   3426             /* Sets Variable Latency */
   3427             SOC_IF_ERROR_RETURN
   3428                (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7,
   3429                                                    0x0004, 0x0004));
   3430             /* Setting GPHY core, MII buffer register as well */
   3431             SOC_IF_ERROR_RETURN
   3432                (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc,
   3433                                                         0x0004, 0x0004));
   3434         } else {
   3435             /* Sets Fixed Latency */
   3436             SOC_IF_ERROR_RETURN
   3437                (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 7,
   3438                                                    0x0000, 0x0004));
   3439             /* Setting GPHY core, MII buffer register as well */
   3440             SOC_IF_ERROR_RETURN
   3441                (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 
   3442                                                         0x0000, 0x0004));
   3443         } 
   3444         break;
   3445 
   3446 
   3447     case SOC_PHY_CONTROL_EEE_AUTO_BUFFER_LIMIT:
   3448         /* Buffer limit modification is not allowed */
   3449 
   3450     case SOC_PHY_CONTROL_EEE_TRANSMIT_WAKE_TIME:
   3451     case SOC_PHY_CONTROL_EEE_RECEIVE_WAKE_TIME:
   3452     case SOC_PHY_CONTROL_EEE_TRANSMIT_SLEEP_TIME:
   3453     case SOC_PHY_CONTROL_EEE_RECEIVE_SLEEP_TIME:
   3454     case SOC_PHY_CONTROL_EEE_TRANSMIT_QUIET_TIME:
   3455     case SOC_PHY_CONTROL_EEE_RECEIVE_QUIET_TIME:
   3456     case SOC_PHY_CONTROL_EEE_TRANSMIT_REFRESH_TIME:
   3457         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3458             rv = SOC_E_UNAVAIL;
   3459         }
   3460 
   3461         /* Time modification not allowed, IEEE EEE spec constants */
   3462         rv = SOC_E_UNAVAIL;
   3463         break;
   3464 
   3465     case SOC_PHY_CONTROL_EEE_STATISTICS_CLEAR:
   3466         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3467             rv = SOC_E_UNAVAIL;
   3468         }
   3469         
   3470         if (value == 1) {
   3471             /* Clearing the stats: Enable clear on Read  */
   3472             SOC_IF_ERROR_RETURN
   3473                (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 
   3474                                                         0x1000, 0x1000));
   3475 
   3476             /* Read all the stats to clear */
   3477             SOC_IF_ERROR_RETURN
   3478                 (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data));
   3479             SOC_IF_ERROR_RETURN
   3480                 (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data));
   3481             SOC_IF_ERROR_RETURN
   3482                 (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data));
   3483             SOC_IF_ERROR_RETURN
   3484                 (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data));
   3485             SOC_IF_ERROR_RETURN
   3486                 (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data));
   3487             SOC_IF_ERROR_RETURN
   3488                 (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data));
   3489             SOC_IF_ERROR_RETURN
   3490                 (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data));
   3491             SOC_IF_ERROR_RETURN
   3492                 (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data));
   3493 
   3494             /* Disable Clear on Read  */
   3495             SOC_IF_ERROR_RETURN
   3496                (MODIFY_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, 
   3497                                                         0x0000, 0x1000));
   3498         }
   3499 
   3500         break;
   3501 
   3502     case SOC_PHY_CONTROL_LOOPBACK_EXTERNAL:
   3503         if (value) {
   3504             int saved_autoneg, saved_speed;
   3505 
   3506             saved_autoneg = pc->copper.autoneg_enable;
   3507             SOC_IF_ERROR_RETURN
   3508                 (phy_54682_autoneg_set(unit, port, 0));
   3509             pc->copper.autoneg_enable = saved_autoneg;
   3510             
   3511             saved_speed = pc->copper.force_speed;
   3512             SOC_IF_ERROR_RETURN
   3513                 (phy_54682_speed_set(unit, port, 1000));
   3514             pc->copper.force_speed = saved_speed;
   3515 
   3516             SOC_IF_ERROR_RETURN
   3517                 (MODIFY_PHY54682_MII_GB_CTRLr(unit, pc, (1U << 12 | 1U << 11), (1U << 12 | 1U << 11)));
   3518             SOC_IF_ERROR_RETURN
   3519                 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, (1U << 15 | 1U << 10), (1U << 15 | 1U << 10)));
   3520         } else {
   3521             SOC_IF_ERROR_RETURN
   3522                 (MODIFY_PHY54682_MII_GB_CTRLr(unit, pc, 0, (1U << 12 | 1U << 11)));
   3523             SOC_IF_ERROR_RETURN
   3524                 (MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0, (1U << 15 | 1U << 10)));
   3525             SOC_IF_ERROR_RETURN
   3526                 (phy_54682_speed_set(unit, port, pc->copper.force_speed));
   3527             SOC_IF_ERROR_RETURN
   3528                 (phy_54682_autoneg_set(unit, port, pc->copper.autoneg_enable ? 1 : 0));
   3529         }
   3530         break;
   3531 
   3532     default:
   3533         rv = SOC_E_UNAVAIL;
   3534         break;
   3535     }
   3536     return rv;
   3537 }
   3538 /*
   3539  * Function:
   3540  *      phy_54682_control_get
   3541  * Purpose:
   3542  *      Get current control settign of the PHY.
   3543  * Parameters:
   3544  *      unit  - StrataSwitch unit #.
   3545  *      port  - StrataSwitch port #.
   3546  *      type  - Control to update
   3547  *      value - (OUT)Current setting for the control
   3548  * Returns:
   3549  *      SOC_E_NONE
   3550  */
   3551 STATIC int
   3552 phy_54682_control_get(int unit, soc_port_t port,
   3553                      soc_phy_control_t type, uint32 *value)
   3554 {
   3555     int rv;
   3556     phy_ctrl_t *pc;
   3557     uint16 data;
   3558     uint32 temp;
   3559     soc_port_t primary;
   3560     int offset;
   3561 
   3562     PHY_CONTROL_TYPE_CHECK(type);
   3563 
   3564     pc = EXT_PHY_SW_STATE(unit, port);
   3565     rv = SOC_E_NONE;
   3566     switch(type) {
   3567         case SOC_PHY_CONTROL_PREEMPHASIS:
   3568             /* fall through */
   3569         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   3570             rv = _phy_54682_tx_control_get(unit, port, type, value);
   3571             break;
   3572 
   3573         case SOC_PHY_CONTROL_POWER:
   3574             *value = pc->power_mode;
   3575         break;
   3576 
   3577     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   3578         SOC_IF_ERROR_RETURN
   3579             (READ_PHY54682_AUTO_POWER_DOWNr(unit,pc, &data));
   3580 
   3581         if (data & PHY_54682_AUTO_PWRDWN_SLEEP_MASK) {
   3582             *value = PHY_54682_AUTO_PWRDWN_SLEEP_MAX;
   3583         } else {
   3584             *value = 2700;
   3585         }
   3586         break;
   3587 
   3588     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   3589         SOC_IF_ERROR_RETURN
   3590             (READ_PHY54682_AUTO_POWER_DOWNr(unit,pc, &data));
   3591 
   3592         data &= PHY_54682_AUTO_PWRDWN_WAKEUP_MASK;
   3593         *value = data * PHY_54682_AUTO_PWRDWN_WAKEUP_UNIT;
   3594         break;
   3595 
   3596     case SOC_PHY_CONTROL_PORT_PRIMARY:
   3597         SOC_IF_ERROR_RETURN
   3598             (soc_phyctrl_primary_get(unit, port, &primary));
   3599         *value = (uint32) primary;
   3600         break;
   3601 
   3602     case SOC_PHY_CONTROL_PORT_OFFSET:
   3603         SOC_IF_ERROR_RETURN
   3604             (soc_phyctrl_offset_get(unit, port, &offset));
   3605         *value = (uint32) offset;
   3606         break;
   3607 
   3608     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   3609         SOC_IF_ERROR_RETURN
   3610             (soc_phyctrl_primary_get(unit, port, &primary));
   3611         SOC_IF_ERROR_RETURN
   3612             (soc_phyctrl_offset_get(unit, port, &offset));
   3613         if (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) {
   3614             if (( data & 0x8 ) || (( data & 0x7 ) != offset)) {
   3615                 *value = FALSE;
   3616             } else {
   3617                 *value = TRUE;
   3618             }
   3619         }
   3620         break;
   3621 
   3622     case SOC_PHY_CONTROL_CLOCK_SECONDARY_ENABLE:
   3623         SOC_IF_ERROR_RETURN
   3624             (soc_phyctrl_primary_get(unit, port, &primary));
   3625         SOC_IF_ERROR_RETURN
   3626             (soc_phyctrl_offset_get(unit, port, &offset));
   3627         if (phy_54682_toplvl_reg_read(unit, port, primary, 0x0, &data) == SOC_E_NONE) {
   3628             if (( data & (0x8<<4) ) || (( data & (0x7<<4) ) != (offset<<4) )) {
   3629                 *value = FALSE;
   3630             } else {
   3631                 *value = TRUE;
   3632             }
   3633         }
   3634         break;
   3635 
   3636     case SOC_PHY_CONTROL_CLOCK_FREQUENCY:
   3637         do {
   3638             pc->phy_id =  PHY54682_SLICE_ADDR(pc, 1);
   3639             SOC_IF_ERROR_BREAK
   3640                 (READ_PHY54682_EXP_SERDES_MULTIPLIER_CTRLr(unit, pc, &data), rv);
   3641             if ((data >> 9) & 0x1) {
   3642                 *value = 156250;
   3643             } else {
   3644                 *value = 125000;
   3645             }
   3646         } while(0);
   3647         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   3648         break;
   3649 
   3650     case SOC_PHY_CONTROL_EEE:
   3651         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3652             rv = SOC_E_UNAVAIL;
   3653         }
   3654         *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) &&
   3655                  !PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0;
   3656         break;
   3657 
   3658     case SOC_PHY_CONTROL_EEE_AUTO:
   3659         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3660             rv = SOC_E_UNAVAIL;
   3661         }
   3662         *value = (PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_ENABLED) &&
   3663                   PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_MODE)) ? 1 : 0;
   3664         break;
   3665 
   3666     case SOC_PHY_CONTROL_EEE_AUTO_FIXED_LATENCY:
   3667         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3668             rv = SOC_E_UNAVAIL;
   3669         }
   3670         SOC_IF_ERROR_RETURN
   3671             (READ_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data));
   3672         *value = ((data & 0x0004) == 0);
   3673         break;
   3674 
   3675     case SOC_PHY_CONTROL_EEE_AUTO_IDLE_THRESHOLD:
   3676         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3677             rv = SOC_E_UNAVAIL;
   3678         }
   3679         SOC_IF_ERROR_RETURN
   3680             (READ_PHY54682_EXP_MII_BUF_CNTL_STAT1r(unit, pc, &data));
   3681         *value = ((data & 0x0700) >> 8);
   3682         break;
   3683 
   3684     case SOC_PHY_CONTROL_EEE_TRANSMIT_EVENTS:
   3685         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3686             rv = SOC_E_UNAVAIL;
   3687         }
   3688         SOC_IF_ERROR_RETURN
   3689             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   3690         SOC_IF_ERROR_RETURN
   3691             (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data));
   3692         temp = data;
   3693         SOC_IF_ERROR_RETURN
   3694             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   3695         SOC_IF_ERROR_RETURN
   3696             (READ_PHY54682_EXP_EEE_TX_EVENTSr(unit, pc, &data));
   3697         temp |= (data << 16);
   3698         *value = temp;
   3699 
   3700         break;
   3701 
   3702     case SOC_PHY_CONTROL_EEE_TRANSMIT_DURATION:
   3703         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3704             rv = SOC_E_UNAVAIL;
   3705         }
   3706         SOC_IF_ERROR_RETURN
   3707             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   3708         SOC_IF_ERROR_RETURN
   3709             (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data));
   3710         temp = data;
   3711         SOC_IF_ERROR_RETURN
   3712             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   3713         SOC_IF_ERROR_RETURN
   3714             (READ_PHY54682_EXP_EEE_TX_DURATIONr(unit, pc, &data));
   3715         temp |= (data << 16);
   3716         *value = temp;
   3717 
   3718         break;
   3719 
   3720     case SOC_PHY_CONTROL_EEE_RECEIVE_EVENTS:
   3721         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3722             rv = SOC_E_UNAVAIL;
   3723         }
   3724         SOC_IF_ERROR_RETURN
   3725             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   3726         SOC_IF_ERROR_RETURN
   3727             (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data));
   3728         temp = data;
   3729         SOC_IF_ERROR_RETURN
   3730             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   3731         SOC_IF_ERROR_RETURN
   3732             (READ_PHY54682_EXP_EEE_RX_EVENTSr(unit, pc, &data));
   3733         temp |= (data << 16);
   3734         *value = temp;
   3735 
   3736         break;
   3737 
   3738     case SOC_PHY_CONTROL_EEE_RECEIVE_DURATION:
   3739         if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) {
   3740             rv = SOC_E_UNAVAIL;
   3741         }
   3742         SOC_IF_ERROR_RETURN
   3743             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 0x0, 1U<<14)); /* exp af */
   3744         SOC_IF_ERROR_RETURN
   3745             (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data));
   3746         temp = data;
   3747         SOC_IF_ERROR_RETURN
   3748             (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FAF,0x15, 1U<<14, 1U<<14)); /* exp af */
   3749         SOC_IF_ERROR_RETURN
   3750             (READ_PHY54682_EXP_EEE_RX_DURATIONr(unit, pc, &data));
   3751         temp |= (data << 16);
   3752         *value = temp;
   3753         break;
   3754 
   3755     case SOC_PHY_CONTROL_LOOPBACK_EXTERNAL:
   3756          SOC_IF_ERROR_RETURN
   3757              (READ_PHY54682_MII_AUX_CTRLr(unit, pc, &data));
   3758          *value = data & (1U<<15) ? 1 : 0;
   3759          break;
   3760 
   3761     default:
   3762         rv = SOC_E_UNAVAIL;
   3763         break;
   3764     }
   3765     return rv;
   3766 }
   3767 
   3768 /*
   3769  * Function:
   3770  *      phy_54682_cable_diag
   3771  * Purpose:
   3772  *      Run 546x cable diagnostics
   3773  * Parameters:
   3774  *      unit - device number
   3775  *      port - port number
   3776  *      status - (OUT) cable diagnotic status structure
   3777  * Returns:     
   3778  *      SOC_E_XXX
   3779  */
   3780 STATIC int
   3781 phy_54682_cable_diag(int unit, soc_port_t port,
   3782                     soc_port_cable_diag_t *status)
   3783 {
   3784     int rv, rv2, i;
   3785     phy_ctrl_t *pc;
   3786 
   3787     extern int phy_5464_cable_diag_sw(int, soc_port_t , 
   3788                                       soc_port_cable_diag_t *);
   3789     pc = EXT_PHY_SW_STATE(unit, port);
   3790 
   3791     if (status == NULL) {
   3792         return SOC_E_PARAM;
   3793     }
   3794 
   3795     status->state = SOC_PORT_CABLE_STATE_OK;
   3796     status->npairs = 4;
   3797     status->fuzz_len = 0;
   3798     for (i = 0; i < 4; i++) {
   3799         status->pair_state[i] = SOC_PORT_CABLE_STATE_OK;
   3800     }
   3801 
   3802     MIIM_LOCK(unit);    /* this locks out linkscan, essentially */
   3803     rv = phy_5464_cable_diag_sw(unit,port, status);
   3804     MIIM_UNLOCK(unit);
   3805     rv2 = 0;
   3806     if (rv <= 0) {      /* don't reset if > 0 -- link was up */
   3807         rv2 = _phy_54682_reset_setup(unit, port);
   3808         if (SOC_SUCCESS(rv2)) {
   3809             rv2 = _phy_54682_medium_config_update(unit, port, &pc->copper);
   3810         }
   3811     }
   3812     if (rv >= 0 && rv2 < 0) {
   3813         return rv2;
   3814     }
   3815     return rv;
   3816 }
   3817 
   3818 STATIC int
   3819 phy54682_cable_diag_dispatch(int unit, soc_port_t port,
   3820             soc_port_cable_diag_t *status)
   3821 {
   3822     phy_ctrl_t *pc;
   3823 
   3824     pc = EXT_PHY_SW_STATE(unit, port);
   3825 
   3826     if (ECD_ENABLE && (((PHY_IS_BCM54682E_OR_BCM54685E(pc)) || (PHY_IS_BCM54684E(pc))) && ((pc->phy_rev & 0x7) > 0x2))) {
   3827         SOC_IF_ERROR_RETURN(
   3828             phy_ecd_cable_diag(unit, port, status));
   3829         SOC_IF_ERROR_RETURN(
   3830             _phy_54682_reset_setup(unit, port));
   3831     } else {
   3832         SOC_IF_ERROR_RETURN(
   3833             phy_54682_cable_diag(unit, port, status));
   3834     }
   3835 
   3836     return SOC_E_NONE;
   3837 }
   3838 
   3839 /*
   3840  * Function:
   3841  *      phy_54682_probe
   3842  * Purpose:
   3843  *      Complement the generic phy probe routine to identify this phy when its
   3844  *      phy id0 and id1 is same as some other phy's.
   3845  * Parameters:
   3846  *      unit - StrataSwitch unit #.
   3847  *      pc   - phy ctrl descriptor.
   3848  * Returns:
   3849  *      SOC_E_NONE,SOC_E_NOT_FOUND
   3850  */
   3851 
   3852 STATIC int
   3853 phy_54682_probe(int unit, phy_ctrl_t *pc)
   3854 {
   3855     uint16 id0, id1;
   3856     soc_phy_info_t *pi;
   3857 
   3858     if (READ_PHY54682_MII_PHY_ID0r(unit, pc, &id0) < 0) {
   3859         return SOC_E_NOT_FOUND;
   3860     }
   3861     if (READ_PHY54682_MII_PHY_ID1r(unit, pc, &id1) < 0) {
   3862         return SOC_E_NOT_FOUND;
   3863     }
   3864     if (id1 & 0x8) {
   3865         pi = &SOC_PHY_INFO(unit, pc->port);
   3866         pi->phy_name = "BCM54685E";
   3867     }
   3868     return SOC_E_NONE;
   3869 }
   3870 
   3871 STATIC int
   3872 phy_54682_link_up(int unit, soc_port_t port)
   3873 {
   3874     phy_ctrl_t *pc;
   3875     int speed = 0;
   3876     uint16 value;
   3877 
   3878     pc = EXT_PHY_SW_STATE(unit, port);
   3879 
   3880     SOC_IF_ERROR_RETURN
   3881         (phy_54682_speed_get(unit, port, &speed));
   3882 
   3883     if (speed == 100) {
   3884         SOC_IF_ERROR_RETURN(
   3885             READ_PHY_REG(unit, pc, 0x11, &value));
   3886         if(value & (1U << 13)) {
   3887                 SOC_IF_ERROR_RETURN
   3888                     (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 0x0<<10, 0x3<<10)); /* exp reg f5 */
   3889         } else {
   3890                 SOC_IF_ERROR_RETURN
   3891                     (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 0x1<<10, 0x3<<10)); /* exp reg f5 */
   3892         }
   3893     }
   3894 
   3895     if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { /*non EEE */
   3896         /* do nothing */
   3897     } else
   3898     if ((pc->phy_rev & 0x6) == 0x0) {
   3899     /* revs A0 and A1 of supported PHYs */
   3900         uint32 eee_auto;
   3901 
   3902         SOC_IF_ERROR_RETURN
   3903             (phy_54682_control_get(unit, port,
   3904                      SOC_PHY_CONTROL_EEE_AUTO, &eee_auto));
   3905         if ((speed == 100) && (eee_auto == 1)) {
   3906             SOC_IF_ERROR_RETURN(
   3907                 WRITE_PHY_REG(unit, pc, 0x17, 0x0d10));
   3908             SOC_IF_ERROR_RETURN(
   3909                 WRITE_PHY_REG(unit, pc, 0x15, 0x00ff));
   3910 
   3911         } else {
   3912             SOC_IF_ERROR_RETURN(
   3913                 WRITE_PHY_REG(unit, pc, 0x17, 0x0d10));
   3914             SOC_IF_ERROR_RETURN(
   3915                 WRITE_PHY_REG(unit, pc, 0x15, 0x0000));
   3916         }
   3917     } else if ((pc->phy_rev & 0x6) == 0x2) {
   3918         /* revs B0 and B1 of supported PHYs */
   3919         sal_usleep(10000);
   3920         SOC_IF_ERROR_RETURN(
   3921             MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, (1U << 11), (1U << 11)));
   3922         SOC_IF_ERROR_RETURN(
   3923             WRITE_PHY_REG(unit, pc, 0x17, 0x001a));
   3924         SOC_IF_ERROR_RETURN(
   3925             WRITE_PHY_REG(unit, pc, 0x15, 0x0003));
   3926         SOC_IF_ERROR_RETURN(
   3927             MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0, (1U << 11)));
   3928     }
   3929 
   3930     /* Notify interface to internal PHY */
   3931     SOC_IF_ERROR_RETURN
   3932         (soc_phyctrl_notify(unit, port, phyEventInterface, SOC_PORT_IF_SGMII));
   3933 
   3934     /* Situation observed with Saber devices XGXS16g1l+BCM54682E
   3935        Linkscan is not updating speed for internal phy xgxs16g1l. 
   3936        It was observed that when speed is set to 100M the int phy 
   3937        is still set to 1G and traffic does not flow through untill 
   3938        int phy speed is also update to 100M. This applies to other 
   3939        speeds as well. 
   3940        Explicitly send speed notify to int phy from ext phy.
   3941     */
   3942     SOC_IF_ERROR_RETURN
   3943         (soc_phyctrl_notify(unit, port, phyEventSpeed, speed));
   3944 
   3945     return SOC_E_NONE;
   3946 }
   3947 
   3948 STATIC int
   3949 phy_54682_link_down(int unit, soc_port_t port)
   3950 {
   3951     phy_ctrl_t *pc;
   3952 
   3953     if (!PHY_FLAGS_TST(unit, port, PHY_FLAGS_EEE_CAPABLE)) { /*non EEE */
   3954         return SOC_E_NONE;
   3955     }
   3956 
   3957     pc = EXT_PHY_SW_STATE(unit, port);
   3958 
   3959     if ((pc->phy_rev & 0x6) == 0x2) {
   3960         /* revs B0 and B1 of supported PHYs */
   3961         SOC_IF_ERROR_RETURN(
   3962             MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, (1U << 11), (1U << 11)));
   3963         SOC_IF_ERROR_RETURN(
   3964             WRITE_PHY_REG(unit, pc, 0x17, 0x001a));
   3965         SOC_IF_ERROR_RETURN(
   3966             WRITE_PHY_REG(unit, pc, 0x15, 0x0007));
   3967         SOC_IF_ERROR_RETURN(
   3968             MODIFY_PHY54682_MII_AUX_CTRLr(unit, pc, 0, (1U << 11)));
   3969  
   3970     }
   3971 
   3972     return (SOC_E_NONE);
   3973 }
   3974 
   3975 void _phy_54682e_encode_egress_message_mode(soc_port_phy_timesync_event_message_egress_mode_t mode,
   3976                                             int offset, uint16 *value)
   3977 {
   3978 
   3979     switch (mode) {
   3980     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE:
   3981         *value |= (0x0 << offset);
   3982         break;
   3983     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD:
   3984         *value |= (0x1 << offset);
   3985         break;
   3986     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN:
   3987         *value |= (0x2 << offset);
   3988         break;
   3989     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP:
   3990         *value |= (0x3 << offset);
   3991         break;
   3992     default:
   3993         break;
   3994     }
   3995 
   3996 }
   3997 
   3998 void _phy_54682e_encode_ingress_message_mode(soc_port_phy_timesync_event_message_ingress_mode_t mode,
   3999                                             int offset, uint16 *value)
   4000 {
   4001 
   4002     switch (mode) {
   4003     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE:
   4004         *value |= (0x0 << offset);
   4005         break;
   4006     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD:
   4007         *value |= (0x1 << offset);
   4008         break;
   4009     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP:
   4010         *value |= (0x2 << offset);
   4011         break;
   4012     case SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME:
   4013         *value |= (0x3 << offset);
   4014         break;
   4015     default:
   4016         break;
   4017     }
   4018 
   4019 }
   4020 
   4021 void _phy_54682e_decode_egress_message_mode(uint16 value, int offset,
   4022                                             soc_port_phy_timesync_event_message_egress_mode_t *mode)
   4023 {
   4024 
   4025     switch ((value >> offset) & 0x3) {
   4026     case 0x0:
   4027         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_NONE;
   4028         break;
   4029     case 0x1:
   4030         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_UPDATE_CORRECTIONFIELD;
   4031         break;
   4032     case 0x2:
   4033         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_REPLACE_CORRECTIONFIELD_ORIGIN;
   4034         break;
   4035     case 0x3:
   4036         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_EGRESS_MODE_CAPTURE_TIMESTAMP;
   4037         break;
   4038     }
   4039 
   4040 }
   4041 
   4042 void _phy_54682e_decode_ingress_message_mode(uint16 value, int offset,
   4043                                             soc_port_phy_timesync_event_message_ingress_mode_t *mode)
   4044 {
   4045 
   4046     switch ((value >> offset) & 0x3) {
   4047     case 0x0:
   4048         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_NONE;
   4049         break;
   4050     case 0x1:
   4051         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_UPDATE_CORRECTIONFIELD;
   4052         break;
   4053     case 0x2:
   4054         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_TIMESTAMP;
   4055         break;
   4056     case 0x3:
   4057         *mode = SOC_PORT_PHY_TIMESYNC_EVENT_MESSAGE_INGRESS_MODE_INSERT_DELAYTIME;
   4058         break;
   4059     }
   4060 
   4061 }
   4062 
   4063 void _phy_54682e_encode_gmode(soc_port_phy_timesync_global_mode_t mode,
   4064                                             uint16 *value)
   4065 {
   4066 
   4067     switch (mode) {
   4068     case SOC_PORT_PHY_TIMESYNC_MODE_FREE:
   4069         *value = 0x1;
   4070         break;
   4071     case SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN:
   4072         *value = 0x2;
   4073         break;
   4074     case SOC_PORT_PHY_TIMESYNC_MODE_CPU:
   4075         *value = 0x3;
   4076         break;
   4077     default:
   4078         break;
   4079     }
   4080 
   4081 }
   4082 
   4083 void _phy_54682e_decode_gmode(uint16 value,
   4084                                             soc_port_phy_timesync_global_mode_t *mode)
   4085 {
   4086 
   4087     switch (value & 0x3) {
   4088     case 0x1:
   4089         *mode = SOC_PORT_PHY_TIMESYNC_MODE_FREE;
   4090         break;
   4091     case 0x2:
   4092         *mode = SOC_PORT_PHY_TIMESYNC_MODE_SYNCIN;
   4093         break;
   4094     case 0x3:
   4095         *mode = SOC_PORT_PHY_TIMESYNC_MODE_CPU;
   4096         break;
   4097     default:
   4098         break;
   4099     }
   4100 
   4101 }
   4102 
   4103 void _phy_54682e_encode_framesync_mode(soc_port_phy_timesync_framesync_mode_t mode,
   4104                                             uint16 *value)
   4105 {
   4106 
   4107     switch (mode) {
   4108     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0:
   4109         *value = 1U << 0;
   4110         break;
   4111     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1:
   4112         *value = 1U << 1;
   4113         break;
   4114     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT:
   4115         *value = 1U << 2;
   4116         break;
   4117     case SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU:
   4118         *value = 1U << 3;
   4119         break;
   4120     default:
   4121         break;
   4122     }
   4123 
   4124 }
   4125 
   4126 void _phy_54682e_decode_framesync_mode(uint16 value,
   4127                                             soc_port_phy_timesync_framesync_mode_t *mode)
   4128 {
   4129 
   4130     switch (value & 0xf) {
   4131     case 1U << 0:
   4132         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN0;
   4133         break;
   4134     case 1U << 1:
   4135         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCIN1;
   4136         break;
   4137     case 1U << 2:
   4138         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_SYNCOUT;
   4139         break;
   4140     case 1U << 3:
   4141         *mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_CPU;
   4142         break;
   4143     default:
   4144         break;
   4145     }
   4146 
   4147 }
   4148 
   4149 void _phy_54682e_encode_syncout_mode(soc_port_phy_timesync_syncout_mode_t mode,
   4150                                             uint16 *value)
   4151 {
   4152 
   4153     switch (mode) {
   4154     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE:
   4155         *value = 0x0;
   4156         break;
   4157     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME:
   4158         *value = 0x1;
   4159         break;
   4160     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN:
   4161         *value = 0x2;
   4162         break;
   4163     case SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC:
   4164         *value = 0x3;
   4165         break;
   4166     default:
   4167         break;
   4168     }
   4169 
   4170 }
   4171 
   4172 void _phy_54682e_decode_syncout_mode(uint16 value,
   4173                                             soc_port_phy_timesync_syncout_mode_t *mode)
   4174 {
   4175 
   4176     switch (value & 0x3) {
   4177     case 0x0:
   4178         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE;
   4179         break;
   4180     case 0x1:
   4181         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_ONE_TIME;
   4182         break;
   4183     case 0x2:
   4184         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN;
   4185         break;
   4186     case 0x3:
   4187         *mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_PULSE_TRAIN_WITH_SYNC;
   4188         break;
   4189     }
   4190 
   4191 }
   4192 
   4193 
   4194 STATIC int
   4195 phy_54682_timesync_config_set(int unit, soc_port_t port, soc_port_phy_timesync_config_t *conf)
   4196 {
   4197     phy_ctrl_t *pc;
   4198     int offset, rv = SOC_E_NONE;
   4199     uint16 rx_control_reg = 0, tx_control_reg = 0, rx_crc_control_reg = 0,
   4200            en_control_reg = 0, tx_capture_en_reg = 0, rx_capture_en_reg = 0,
   4201            nse_nco_6 = 0, nse_nco_2c = 0, value, mask,
   4202            gmode = 0, framesync_mode = 0, syncout_mode = 0,
   4203            pulse_1_length, pulse_2_length, length_threshold, event_offset;
   4204     uint32 interval;
   4205 
   4206     pc = EXT_PHY_SW_STATE(unit, port);
   4207 
   4208     if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) {
   4209         return SOC_E_UNAVAIL;
   4210     }
   4211 
   4212     offset = PHY54682_DEV_PHY_SLICE(pc);
   4213 
   4214     do {
   4215         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) {
   4216 
   4217             if (conf->flags & SOC_PORT_PHY_TIMESYNC_ENABLE) {
   4218                 en_control_reg |= ((1U << (offset + 8)) | (1U << offset));
   4219                 nse_nco_6 |= (1U << 12); /* NSE init */
   4220 
   4221                 SOC_IF_ERROR_BREAK
   4222                     (MODIFY_PHY54682_SGMII_SLAVEr(unit, pc, 0x02, 0x02), rv);
   4223 
   4224                 SOC_IF_ERROR_BREAK
   4225                     (MODIFY_PHY54682_EXT_SERDES_CTRLr(unit, pc, 0x00, 0x01), rv);
   4226 
   4227                 SOC_IF_ERROR_BREAK
   4228                     (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 1U<<0, 1U<<0), rv); /* exp reg f5 */
   4229             } else {
   4230 
   4231                 SOC_IF_ERROR_BREAK
   4232                     (PHY54682_REG_MODIFY(unit, pc, 0x00, 0x0FF5,0x15, 0, 1U<<0), rv); /* exp reg f5 */
   4233 
   4234             }
   4235 
   4236             /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   4237             pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   4238 
   4239             SOC_IF_ERROR_BREAK
   4240                 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x10, en_control_reg, 
   4241                                            ((1U << (offset + 8)) | (1U << offset))), rv);
   4242 
   4243             SOC_IF_ERROR_BREAK
   4244                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x10, &en_control_reg), rv);
   4245 
   4246             if (conf->flags & SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE) {
   4247                 tx_capture_en_reg |= (1U << offset);
   4248                 rx_capture_en_reg |= (1U << (offset + 8));
   4249             }
   4250 
   4251             SOC_IF_ERROR_BREAK
   4252                 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x12, tx_capture_en_reg, 
   4253                                            (1U << offset)), rv);
   4254 
   4255             SOC_IF_ERROR_BREAK
   4256                 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x13, rx_capture_en_reg, 
   4257                                            (1U << (offset + 8))), rv);
   4258 
   4259             if (conf->flags & SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE) {
   4260                 nse_nco_6 |= (1U << 13);
   4261             }
   4262 
   4263             SOC_IF_ERROR_BREAK
   4264                 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x4f, nse_nco_6, 
   4265                                            (1U << 13)), rv);
   4266 
   4267             if (conf->flags & SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE) {
   4268                 rx_crc_control_reg |= (1U << 3);
   4269             }
   4270 
   4271             SOC_IF_ERROR_BREAK
   4272                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x34, rx_crc_control_reg), rv);
   4273 
   4274             if (conf->flags & SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE) {
   4275                 rx_control_reg |= (1U << 3);
   4276                 tx_control_reg |= (1U << 3);
   4277             }
   4278 
   4279             if (conf->flags & SOC_PORT_PHY_TIMESYNC_L2_ENABLE) {
   4280                 rx_control_reg |= (1U << 2);
   4281                 tx_control_reg |= (1U << 2);
   4282             }
   4283 
   4284             if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP4_ENABLE) {
   4285                 rx_control_reg |= (1U << 1);
   4286                 tx_control_reg |= (1U << 1);
   4287             }
   4288 
   4289             if (conf->flags & SOC_PORT_PHY_TIMESYNC_IP6_ENABLE) {
   4290                 rx_control_reg |= (1U << 0);
   4291                 tx_control_reg |= (1U << 0);
   4292             }
   4293 
   4294             SOC_IF_ERROR_BREAK
   4295                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x32, tx_control_reg), rv);
   4296                                               
   4297             SOC_IF_ERROR_BREAK
   4298                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x33, rx_control_reg), rv);
   4299                                               
   4300             if (conf->flags & SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT) {
   4301                 nse_nco_2c &= (uint16) ~(1U << 14);
   4302             } else {
   4303                 nse_nco_2c |= (1U << 14);
   4304             }
   4305 
   4306             SOC_IF_ERROR_BREAK
   4307                 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x47, nse_nco_2c, 
   4308                                                (1U << 14)), rv);
   4309         }
   4310 
   4311         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) {
   4312             /* VLAN TAG register */
   4313             SOC_IF_ERROR_BREAK
   4314                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x35, conf->itpid), rv);
   4315         }
   4316 
   4317         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) {
   4318             /* OUTER VLAN TAG register */
   4319             SOC_IF_ERROR_BREAK
   4320                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x36, conf->otpid), rv);
   4321         }
   4322 
   4323         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) {
   4324             /* INNER VLAN TAG register */
   4325             SOC_IF_ERROR_BREAK
   4326                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x52, conf->otpid2), rv);
   4327         }
   4328 
   4329         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) {
   4330             SOC_IF_ERROR_BREAK
   4331                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4b, conf->ts_divider & 0xfff), rv);
   4332         }
   4333 
   4334         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) {
   4335             pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   4336 
   4337             SOC_IF_ERROR_BREAK
   4338                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x6f, conf->rx_link_delay & 0xffff), rv);
   4339             SOC_IF_ERROR_BREAK
   4340                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x70, (conf->rx_link_delay >> 16) & 0xffff), rv);
   4341 
   4342            /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   4343             pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   4344         }
   4345 
   4346 
   4347         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) {
   4348             SOC_IF_ERROR_BREAK
   4349                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x25, (uint16)(conf->original_timecode.nanoseconds & 0xffff)), rv);
   4350 
   4351             SOC_IF_ERROR_BREAK
   4352                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x26, (uint16)((conf->original_timecode.nanoseconds >> 16) & 0xffff)), rv);
   4353 
   4354             SOC_IF_ERROR_BREAK
   4355                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x27, (uint16)(COMPILER_64_LO(conf->original_timecode.seconds) & 0xffff)), rv);
   4356 
   4357             SOC_IF_ERROR_BREAK
   4358                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x28, (uint16)((COMPILER_64_LO(conf->original_timecode.seconds) >> 16) & 0xffff)), rv);
   4359 
   4360             SOC_IF_ERROR_BREAK
   4361                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x29, (uint16)(COMPILER_64_HI(conf->original_timecode.seconds) & 0xffff)), rv);
   4362         }
   4363         mask = 0;
   4364 
   4365         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) {
   4366             _phy_54682e_encode_gmode(conf->gmode,&gmode);
   4367             mask |= (0x3 << 14);
   4368         }
   4369 
   4370         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) {
   4371             _phy_54682e_encode_framesync_mode(conf->framesync.mode, &framesync_mode);
   4372             mask |= (0xf << 2) | (0x1 << 11);
   4373 
   4374             /* Divide by 8 */
   4375             length_threshold = conf->framesync.length_threshold >> 3;
   4376             event_offset = conf->framesync.event_offset >> 3;
   4377 
   4378             SOC_IF_ERROR_BREAK
   4379                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x51, length_threshold), rv);
   4380             SOC_IF_ERROR_BREAK
   4381                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x50, event_offset), rv);
   4382         }
   4383 
   4384         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) {
   4385             _phy_54682e_encode_syncout_mode(conf->syncout.mode, &syncout_mode);
   4386             mask |= (0x3 << 0);
   4387 
   4388             /* Divide by 8 */
   4389             interval = conf->syncout.interval >> 3;
   4390             pulse_1_length = conf->syncout.pulse_1_length >> 3;
   4391             pulse_2_length = conf->syncout.pulse_2_length >> 3;
   4392 
   4393             SOC_IF_ERROR_BREAK
   4394                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x48, interval & 0xffff), rv);
   4395             SOC_IF_ERROR_BREAK
   4396                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x49, 
   4397                     ((pulse_2_length & 0x3) << 14) | ((interval >> 16) & 0x3fff)), rv);
   4398             SOC_IF_ERROR_BREAK
   4399                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4a, 
   4400                     ((pulse_1_length & 0x1ff) << 7) | ((pulse_2_length >> 2) & 0x7f)), rv);
   4401 
   4402             SOC_IF_ERROR_BREAK
   4403                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4e, 
   4404                     (uint16)(COMPILER_64_LO(conf->syncout.syncout_ts) & 0xffff)), rv);
   4405             SOC_IF_ERROR_BREAK
   4406                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4d, 
   4407                     (uint16)((COMPILER_64_LO(conf->syncout.syncout_ts) >> 16) & 0xffff)), rv);
   4408             SOC_IF_ERROR_BREAK
   4409                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4c, 
   4410                     (uint16)(COMPILER_64_HI(conf->syncout.syncout_ts) & 0xffff)), rv);
   4411         }
   4412 
   4413         SOC_IF_ERROR_BREAK
   4414             (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x4f, (gmode << 14) |
   4415                 ((framesync_mode & 0x2) ? (1U << 11) : (1U << 6)) | /* if bits 1 or 2 are set, turn off syncout */
   4416                 (framesync_mode << 2) | (syncout_mode << 0), mask), rv);
   4417 
   4418 
   4419         /* tx_timestamp_offset */
   4420         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) {
   4421             SOC_IF_ERROR_BREAK
   4422                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x15 + offset, (uint16)(conf->tx_timestamp_offset & 0xffff)), rv);
   4423 
   4424             if (offset < 4 ) {
   4425                 SOC_IF_ERROR_BREAK
   4426                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x63, 
   4427                         ((conf->tx_timestamp_offset & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv);
   4428             } else {
   4429                 uint16 offset1 = offset - 4;
   4430                 SOC_IF_ERROR_BREAK
   4431                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x64, 
   4432                         ((conf->tx_timestamp_offset & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv);
   4433             }
   4434         }
   4435 
   4436         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) {
   4437             /* rx_timestamp_offset */
   4438             SOC_IF_ERROR_BREAK
   4439                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x1d + offset, (uint16)(conf->rx_timestamp_offset & 0xffff)), rv);
   4440 
   4441             if (offset < 4 ) {
   4442                 SOC_IF_ERROR_BREAK
   4443                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x65, 
   4444                         ((conf->rx_timestamp_offset & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv);
   4445             } else {
   4446                 uint16 offset1 = offset - 4;
   4447                 SOC_IF_ERROR_BREAK
   4448                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x66, 
   4449                         ((conf->rx_timestamp_offset & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv);
   4450             }
   4451         }
   4452 
   4453         value = 0;
   4454         mask = 0;
   4455 
   4456         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) {
   4457             _phy_54682e_encode_egress_message_mode(conf->tx_sync_mode, 0, &value);
   4458             mask |= 0x3 << 0;
   4459         }
   4460 
   4461         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) {
   4462             _phy_54682e_encode_egress_message_mode(conf->tx_delay_request_mode, 2, &value);
   4463             mask |= 0x3 << 2;
   4464         }
   4465 
   4466         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) {
   4467             _phy_54682e_encode_egress_message_mode(conf->tx_pdelay_request_mode, 4, &value);
   4468             mask |= 0x3 << 4;
   4469         }
   4470 
   4471         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) {
   4472             _phy_54682e_encode_egress_message_mode(conf->tx_pdelay_response_mode, 6, &value);
   4473             mask |= 0x3 << 6;
   4474         }
   4475                                                 
   4476         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   4477 
   4478         SOC_IF_ERROR_BREAK
   4479             (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x11, value, mask), rv); 
   4480 
   4481         value = 0;
   4482         mask = 0;
   4483 
   4484         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) {
   4485             _phy_54682e_encode_ingress_message_mode(conf->rx_sync_mode, 0, &value);
   4486             mask |= 0x3 << 0;
   4487         }
   4488 
   4489         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) {
   4490             _phy_54682e_encode_ingress_message_mode(conf->rx_delay_request_mode, 2, &value);
   4491             mask |= 0x3 << 2;
   4492         }
   4493 
   4494         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) {
   4495             _phy_54682e_encode_ingress_message_mode(conf->rx_pdelay_request_mode, 4, &value);
   4496             mask |= 0x3 << 4;
   4497         }
   4498 
   4499         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) {
   4500             _phy_54682e_encode_ingress_message_mode(conf->rx_pdelay_response_mode, 6, &value);
   4501             mask |= 0x3 << 6;
   4502         }
   4503                                                 
   4504                                                 
   4505         SOC_IF_ERROR_BREAK
   4506             (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x12, value << 8, mask << 8), rv); 
   4507 
   4508 
   4509         /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   4510         pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   4511 
   4512         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) {
   4513             /* Initial ref phase [15:0] */
   4514             SOC_IF_ERROR_BREAK
   4515                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x38, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv);
   4516 
   4517             /* Initial ref phase [31:16]  */
   4518             SOC_IF_ERROR_BREAK
   4519                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x39, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_ref_phase) >> 16) & 0xffff)), rv);
   4520 
   4521             /*  Initial ref phase [47:32] */
   4522             SOC_IF_ERROR_BREAK
   4523                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3a, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_ref_phase) & 0xffff)), rv);
   4524         }
   4525 
   4526         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) {
   4527             /* Ref phase delta [15:0] */
   4528             SOC_IF_ERROR_BREAK
   4529                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3b, (uint16)(conf->phy_1588_dpll_ref_phase_delta & 0xffff)), rv);
   4530 
   4531             /* Ref phase delta [31:16]  */
   4532             SOC_IF_ERROR_BREAK
   4533                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3c, (uint16)((conf->phy_1588_dpll_ref_phase_delta >> 16) & 0xffff)), rv);
   4534         }
   4535 
   4536         /* DPLL K1 & K2 */
   4537         mask = 0;
   4538 
   4539         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) {
   4540             mask |= 0xff << 8;
   4541         }
   4542 
   4543         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) {
   4544             mask |= 0xff;
   4545         }
   4546         SOC_IF_ERROR_BREAK
   4547             (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x3d, (conf->phy_1588_dpll_k1 & 0xff)<<8 | (conf->phy_1588_dpll_k2 & 0xff), mask ), rv);
   4548 
   4549         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) {
   4550             /* DPLL K3 */
   4551             SOC_IF_ERROR_BREAK
   4552                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3e, conf->phy_1588_dpll_k3 & 0xff), rv);
   4553         }
   4554 
   4555 
   4556         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) {
   4557             /* Initial loop filter[15:0] */
   4558             SOC_IF_ERROR_BREAK
   4559                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x3f, (uint16)(COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv);
   4560 
   4561             /* Initial loop filter[31:16]  */
   4562             SOC_IF_ERROR_BREAK
   4563                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x40, (uint16)((COMPILER_64_LO(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv);
   4564 
   4565             /*  Initial loop filter[47:32] */
   4566             SOC_IF_ERROR_BREAK
   4567                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x41, (uint16)(COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) & 0xffff)), rv);
   4568 
   4569             /* Initial loop filter[63:48]  */
   4570             SOC_IF_ERROR_BREAK
   4571                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x42, (uint16)((COMPILER_64_HI(conf->phy_1588_dpll_loop_filter) >> 16) & 0xffff)), rv);
   4572         }
   4573     } while(0);
   4574 
   4575     pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   4576 
   4577     return SOC_E_NONE;
   4578 }
   4579 
   4580 STATIC int
   4581 phy_54682_timesync_config_get(int unit, soc_port_t port, soc_port_phy_timesync_config_t *conf)
   4582 {
   4583     phy_ctrl_t *pc;
   4584     int offset, rv = SOC_E_NONE;
   4585     uint16 tx_control_reg = 0, rx_crc_control_reg = 0,
   4586            en_control_reg = 0, tx_capture_en_reg = 0,
   4587            nse_nco_6 = 0, nse_nco_2c = 0, temp1, temp2, temp3, temp4, value;
   4588     soc_port_phy_timesync_global_mode_t gmode = SOC_PORT_PHY_TIMESYNC_MODE_FREE;
   4589     soc_port_phy_timesync_framesync_mode_t framesync_mode = SOC_PORT_PHY_TIMESYNC_FRAMESYNC_NONE;
   4590     soc_port_phy_timesync_syncout_mode_t syncout_mode = SOC_PORT_PHY_TIMESYNC_SYNCOUT_DISABLE;
   4591 
   4592     pc = EXT_PHY_SW_STATE(unit, port);
   4593 
   4594     offset = PHY54682_DEV_PHY_SLICE(pc);
   4595 
   4596     if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) {
   4597         return SOC_E_UNAVAIL;
   4598     }
   4599 
   4600     conf->flags = 0;
   4601 
   4602     do {
   4603         /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   4604         pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   4605 
   4606         SOC_IF_ERROR_BREAK
   4607             (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4f, &nse_nco_6), rv);
   4608 
   4609         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FLAGS) {
   4610             SOC_IF_ERROR_BREAK
   4611                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x10, &en_control_reg), rv); 
   4612 
   4613             if (en_control_reg & (1U << offset)) {
   4614                 conf->flags |= SOC_PORT_PHY_TIMESYNC_ENABLE;
   4615             }
   4616 
   4617             SOC_IF_ERROR_BREAK
   4618                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x12, &tx_capture_en_reg), rv); 
   4619 
   4620             if (tx_capture_en_reg & (1U << offset)) {
   4621                 conf->flags |= SOC_PORT_PHY_TIMESYNC_CAPTURE_TS_ENABLE;
   4622             }
   4623 
   4624             /*
   4625                 SOC_IF_ERROR_BREAK
   4626                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4f, &nse_nco_6), rv);
   4627              */
   4628 
   4629             if (nse_nco_6 & (1U << 13)) {
   4630                 conf->flags |= SOC_PORT_PHY_TIMESYNC_HEARTBEAT_TS_ENABLE;
   4631             }
   4632 
   4633             SOC_IF_ERROR_BREAK
   4634                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x34, &rx_crc_control_reg), rv);
   4635 
   4636             if (rx_crc_control_reg & (1U << 3)) {
   4637                 conf->flags |= SOC_PORT_PHY_TIMESYNC_RX_CRC_ENABLE;
   4638             }
   4639 
   4640             SOC_IF_ERROR_BREAK
   4641                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x32, &tx_control_reg), rv);
   4642                                               
   4643             if (tx_control_reg & (1U << 3)) {
   4644                 conf->flags |= SOC_PORT_PHY_TIMESYNC_8021AS_ENABLE;
   4645             }
   4646 
   4647             if (tx_control_reg & (1U << 2)) {
   4648                 conf->flags |= SOC_PORT_PHY_TIMESYNC_L2_ENABLE;
   4649             }
   4650 
   4651             if (tx_control_reg & (1U << 1)) {
   4652                 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP4_ENABLE;
   4653             }
   4654 
   4655             if (tx_control_reg & (1U << 0)) {
   4656                 conf->flags |= SOC_PORT_PHY_TIMESYNC_IP6_ENABLE;
   4657             }
   4658 
   4659             SOC_IF_ERROR_BREAK
   4660                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x47, &nse_nco_2c), rv);
   4661 
   4662             if (!(nse_nco_2c & (1U << 14))) {
   4663                 conf->flags |= SOC_PORT_PHY_TIMESYNC_CLOCK_SRC_EXT;
   4664             }
   4665         }
   4666 
   4667         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_GMODE) {
   4668             _phy_54682e_decode_gmode((nse_nco_6  >> 14),&gmode);
   4669             conf->gmode = gmode;
   4670         }
   4671 
   4672         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_FRAMESYNC_MODE) {
   4673             _phy_54682e_decode_framesync_mode((nse_nco_6  >> 2), &framesync_mode);
   4674             conf->framesync.mode = framesync_mode;
   4675 
   4676             SOC_IF_ERROR_BREAK
   4677                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x51, &temp1), rv);
   4678             SOC_IF_ERROR_BREAK
   4679                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x50, &temp2), rv);
   4680 
   4681             /* Multiply by 8 */
   4682             conf->framesync.length_threshold = temp1 << 3;
   4683             conf->framesync.event_offset = temp2 << 3;
   4684         }
   4685 
   4686         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_SYNCOUT_MODE) {
   4687             _phy_54682e_decode_syncout_mode((nse_nco_6  >> 0), &syncout_mode);
   4688             conf->syncout.mode = syncout_mode;
   4689 
   4690             SOC_IF_ERROR_BREAK
   4691                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x48, &temp1), rv);
   4692             SOC_IF_ERROR_BREAK
   4693                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x49, &temp2), rv);
   4694             SOC_IF_ERROR_BREAK
   4695                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4a, &temp3), rv);
   4696 
   4697             /* Multiply by 8 */
   4698             conf->syncout.pulse_1_length = ((temp3 >> 7) & 0x1ff) << 3;
   4699             conf->syncout.pulse_2_length =  (((temp3 & 0x7f) << 2) | ((temp2 >> 14) & 0x3)) << 3;
   4700             conf->syncout.interval =  (((temp2 & 0x3fff) << 16) | temp1) << 3;
   4701 
   4702             SOC_IF_ERROR_BREAK
   4703                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4e, &temp1), rv);
   4704             SOC_IF_ERROR_BREAK
   4705                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4d, &temp2), rv);
   4706             SOC_IF_ERROR_BREAK
   4707                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4c, &temp3), rv);
   4708 
   4709             COMPILER_64_SET(conf->syncout.syncout_ts, ((uint32)temp3),  (((uint32)temp2<<16)|((uint32)temp1)));
   4710         }
   4711 
   4712         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ITPID) {
   4713             SOC_IF_ERROR_BREAK
   4714                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x35, &conf->itpid), rv);
   4715         }
   4716 
   4717         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID) {
   4718             SOC_IF_ERROR_BREAK
   4719                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x36, &conf->otpid), rv);
   4720         }
   4721 
   4722         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_OTPID2) {
   4723             SOC_IF_ERROR_BREAK
   4724                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x52, &conf->otpid2), rv);
   4725         }
   4726 
   4727         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TS_DIVIDER) {
   4728             SOC_IF_ERROR_BREAK
   4729                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4b, &conf->ts_divider), rv);
   4730         }
   4731 
   4732         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_LINK_DELAY) {
   4733             offset = PHY54682_DEV_PHY_SLICE(pc);
   4734 
   4735             SOC_IF_ERROR_BREAK
   4736                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x6f, &temp1), rv);
   4737             SOC_IF_ERROR_BREAK
   4738                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x70, &temp2), rv);
   4739 
   4740             conf->rx_link_delay = ((uint32)temp2 << 16) | temp1; 
   4741 
   4742             /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   4743             pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   4744         }
   4745 
   4746         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_ORIGINAL_TIMECODE) {
   4747             SOC_IF_ERROR_BREAK
   4748                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x25, &temp1), rv);
   4749 
   4750             SOC_IF_ERROR_BREAK
   4751                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x26, &temp2), rv);
   4752 
   4753             conf->original_timecode.nanoseconds = ((uint32)temp2 << 16) | temp1; 
   4754 
   4755             SOC_IF_ERROR_BREAK
   4756                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x27, &temp1), rv);
   4757 
   4758             SOC_IF_ERROR_BREAK
   4759                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x28, &temp2), rv);
   4760 
   4761             SOC_IF_ERROR_BREAK
   4762                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x29, &temp3), rv);
   4763 
   4764             /* conf->original_timecode.seconds = ((uint64)temp3 << 32) | ((uint32)temp2 << 16) | temp1; */
   4765 
   4766             COMPILER_64_SET(conf->original_timecode.seconds, ((uint32)temp3),  (((uint32)temp2<<16)|((uint32)temp1)));
   4767         }
   4768 
   4769         /* tx_timestamp_offset */
   4770         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_TIMESTAMP_OFFSET) {
   4771             uint32 temp32;
   4772 
   4773             SOC_IF_ERROR_BREAK
   4774                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x15 + offset, &temp1), rv);
   4775             if (offset < 4 ) {
   4776                 SOC_IF_ERROR_BREAK
   4777                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x63, &temp2), rv);
   4778                 temp32 = (temp2 & (0xf << (offset << 2))) << ((4 - offset) << 2);
   4779             } else {
   4780                 uint16 offset1 = offset - 4;
   4781                 SOC_IF_ERROR_BREAK
   4782                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x64, &temp2), rv);
   4783                 temp32 = (temp2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2);
   4784             }
   4785             conf->tx_timestamp_offset = temp32 | temp1;
   4786         }
   4787 
   4788         /* rx_timestamp_offset */
   4789         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_TIMESTAMP_OFFSET) {
   4790             uint32 temp32;
   4791 
   4792             SOC_IF_ERROR_BREAK
   4793                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x1d + offset, &temp1), rv);
   4794             if (offset < 4 ) {
   4795                 SOC_IF_ERROR_BREAK
   4796                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x65, &temp2), rv);
   4797                 temp32 = (temp2 & (0xf << (offset << 2))) << ((4 - offset) << 2);
   4798             } else {
   4799                 uint16 offset1 = offset - 4;
   4800                 SOC_IF_ERROR_BREAK
   4801                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x66, &temp2), rv);
   4802                 temp32 = (temp2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2);
   4803             }
   4804             conf->rx_timestamp_offset = temp32 | temp1;
   4805         }
   4806 
   4807         pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   4808 
   4809         SOC_IF_ERROR_BREAK
   4810             (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x11, &value), rv); 
   4811 
   4812         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_SYNC_MODE) {
   4813             _phy_54682e_decode_egress_message_mode(value, 0, &conf->tx_sync_mode);
   4814         }
   4815 
   4816         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_DELAY_REQUEST_MODE) {
   4817             _phy_54682e_decode_egress_message_mode(value, 2, &conf->tx_delay_request_mode);
   4818         }
   4819 
   4820         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_REQUEST_MODE) {
   4821             _phy_54682e_decode_egress_message_mode(value, 4, &conf->tx_pdelay_request_mode);
   4822         }
   4823 
   4824         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_TX_PDELAY_RESPONSE_MODE) {
   4825             _phy_54682e_decode_egress_message_mode(value, 6, &conf->tx_pdelay_response_mode);
   4826         }
   4827 
   4828         SOC_IF_ERROR_BREAK
   4829             (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x12, &value), rv); 
   4830 
   4831         value >>= 8;
   4832 
   4833         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_SYNC_MODE) {
   4834             _phy_54682e_decode_ingress_message_mode(value, 0, &conf->rx_sync_mode);
   4835         }
   4836 
   4837         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_DELAY_REQUEST_MODE) {
   4838             _phy_54682e_decode_ingress_message_mode(value, 2, &conf->rx_delay_request_mode);
   4839         }
   4840 
   4841         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_REQUEST_MODE) {
   4842             _phy_54682e_decode_ingress_message_mode(value, 4, &conf->rx_pdelay_request_mode);
   4843         }
   4844 
   4845         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_RX_PDELAY_RESPONSE_MODE) {
   4846             _phy_54682e_decode_ingress_message_mode(value, 6, &conf->rx_pdelay_response_mode);
   4847         }
   4848 
   4849         /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   4850         pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   4851 
   4852         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE) {
   4853             /* Initial ref phase [15:0] */
   4854             SOC_IF_ERROR_BREAK
   4855                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x38, &temp1), rv);
   4856 
   4857             /* Initial ref phase [31:16]  */
   4858             SOC_IF_ERROR_BREAK
   4859                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x39, &temp2), rv);
   4860 
   4861             /*  Initial ref phase [47:32] */
   4862             SOC_IF_ERROR_BREAK
   4863                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3a, &temp3), rv);
   4864 
   4865             COMPILER_64_SET(conf->phy_1588_dpll_ref_phase, ((uint32)temp3), (((uint32)temp2<<16)|((uint32)temp1)));
   4866         }
   4867 
   4868         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_REF_PHASE_DELTA) {
   4869             /* Ref phase delta [15:0] */
   4870             SOC_IF_ERROR_BREAK
   4871                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3b, &temp1), rv);
   4872 
   4873             /* Ref phase delta [31:16]  */
   4874             SOC_IF_ERROR_BREAK
   4875                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3c, &temp2), rv);
   4876 
   4877             conf->phy_1588_dpll_ref_phase_delta = (temp2 << 16) | temp1;
   4878         }
   4879 
   4880         /* DPLL K1 & K2 */
   4881         SOC_IF_ERROR_BREAK
   4882             (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3d, &temp1 ), rv);
   4883 
   4884         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K1) {
   4885             conf->phy_1588_dpll_k1 = (temp1 >> 8 ) & 0xff;
   4886         }
   4887 
   4888         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K2) {
   4889             conf->phy_1588_dpll_k2 = temp1 & 0xff;
   4890         }
   4891 
   4892         /* DPLL K3 */
   4893         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_K3) {
   4894             SOC_IF_ERROR_BREAK
   4895                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3e, &temp1), rv);
   4896             conf->phy_1588_dpll_k3 = temp1 & 0xff;
   4897         }
   4898 
   4899         if (conf->validity_mask & SOC_PORT_PHY_TIMESYNC_VALID_PHY_1588_DPLL_LOOP_FILTER) {
   4900             /* Initial loop filter[15:0] */
   4901             SOC_IF_ERROR_BREAK
   4902                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x3f, &temp1), rv);
   4903 
   4904             /* Initial loop filter[31:16]  */
   4905             SOC_IF_ERROR_BREAK
   4906                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x40, &temp2), rv);
   4907 
   4908             /*  Initial loop filter[47:32] */
   4909             SOC_IF_ERROR_BREAK
   4910                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x41, &temp3), rv);
   4911 
   4912             /* Initial loop filter[63:48]  */
   4913             SOC_IF_ERROR_BREAK
   4914                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x42, &temp4), rv);
   4915 
   4916             COMPILER_64_SET(conf->phy_1588_dpll_loop_filter, (((uint32)temp4<<16)|((uint32)temp3)), (((uint32)temp2<<16)|((uint32)temp1)));
   4917         }
   4918     } while(0);
   4919 
   4920     pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   4921                                             
   4922     return SOC_E_NONE;
   4923 }
   4924 
   4925 STATIC int
   4926 phy_54682_timesync_control_set(int unit, soc_port_t port, soc_port_control_phy_timesync_t type, uint64 value)
   4927 {
   4928     phy_ctrl_t *pc;
   4929     uint16 temp1, temp2;
   4930     uint32 value0;
   4931     int offset, rv = SOC_E_NONE;
   4932 
   4933 
   4934     pc = EXT_PHY_SW_STATE(unit, port);
   4935 
   4936     offset = PHY54682_DEV_PHY_SLICE(pc);
   4937 
   4938     if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) {
   4939         return SOC_E_UNAVAIL;
   4940     }
   4941 
   4942     do {
   4943         /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   4944         pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   4945 
   4946         switch (type) {
   4947         case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP:
   4948         case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP:
   4949             return SOC_E_FAIL;
   4950 
   4951         case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND:
   4952             SOC_IF_ERROR_BREAK
   4953                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x44, (uint16)COMPILER_64_LO(value)), rv);
   4954             break;
   4955 
   4956         case SOC_PORT_CONTROL_PHY_TIMESYNC_FRAMESYNC:
   4957             SOC_IF_ERROR_BREAK
   4958                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x4f, &temp1), rv);
   4959             temp2 = ((temp1 | (0x3 << 14) | (0x1 << 12)) & ~(0xf << 2)) | (0x1 << 5);
   4960             SOC_IF_ERROR_BREAK
   4961                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4f, temp2), rv);
   4962             sal_udelay(1);
   4963             temp2 &= ~((0x1 << 5) | (0x1 << 12));
   4964             SOC_IF_ERROR_BREAK
   4965                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4f, temp2), rv);
   4966             sal_udelay(1);
   4967             SOC_IF_ERROR_BREAK
   4968                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x4f, temp1), rv);
   4969 
   4970             break;
   4971 
   4972         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME:
   4973             COMPILER_64_SHR(value, 4);
   4974             SOC_IF_ERROR_BREAK
   4975                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x45, (uint16)(COMPILER_64_LO(value) & 0xffff)), rv);
   4976             SOC_IF_ERROR_BREAK
   4977                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x46, (uint16)((COMPILER_64_LO(value) >> 16) & 0xffff)), rv);
   4978             SOC_IF_ERROR_BREAK
   4979                 (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x47, (uint16)(COMPILER_64_HI(value) & 0xfff), 0xfff), rv);
   4980             break;
   4981 
   4982         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL:
   4983             temp1 = 0;
   4984             temp2 = 0;
   4985             value0 = COMPILER_64_LO(value);
   4986             if (value0 &  SOC_PORT_PHY_TIMESYNC_TN_LOAD) {
   4987                 temp1 |= 1U << 11;
   4988             }
   4989             if (value0 &  SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD) {
   4990                 temp2 |= 1U << 11;
   4991             }
   4992             if (value0 &  SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD) {
   4993                 temp1 |= 1U << 10;
   4994             }
   4995             if (value0 &  SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD) {
   4996                 temp2 |= 1U << 10;
   4997             }
   4998             if (value0 &  SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD) {
   4999                 temp1 |= 1U << 9;
   5000             }
   5001             if (value0 &  SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD) {
   5002                 temp2 |= 1U << 9;
   5003             }
   5004             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD) {
   5005                 temp1 |= 1U << 8;
   5006             }
   5007             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD) {
   5008                 temp2 |= 1U << 8;
   5009             }
   5010             if (value0 &  SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD) {
   5011                 temp1 |= 1U << 7;
   5012             }
   5013             if (value0 &  SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD) {
   5014                 temp2 |= 1U << 7;
   5015             }
   5016             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD) {
   5017                 temp1 |= 1U << 6;
   5018             }
   5019             if (value0 &  SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD) {
   5020                 temp2 |= 1U << 6;
   5021             }
   5022             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD) {
   5023                 temp1 |= 1U << 5;
   5024             }
   5025             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD) {
   5026                 temp2 |= 1U << 5;
   5027             }
   5028             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD) {
   5029                 temp1 |= 1U << 4;
   5030             }
   5031             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD) {
   5032                 temp2 |= 1U << 4;
   5033             }
   5034             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD) {
   5035                 temp1 |= 1U << 3;
   5036             }
   5037             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD) {
   5038                 temp2 |= 1U << 3;
   5039             }
   5040             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD) {
   5041                 temp1 |= 1U << 2;
   5042             }
   5043             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD) {
   5044                 temp2 |= 1U << 2;
   5045             }
   5046             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD) {
   5047                 temp1 |= 1U << 1;
   5048             }
   5049             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD) {
   5050                 temp2 |= 1U << 1;
   5051             }
   5052             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD) {
   5053                 temp1 |= 1U << 0;
   5054             }
   5055             if (value0 &  SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD) {
   5056                 temp2 |= 1U << 0;
   5057             }
   5058             SOC_IF_ERROR_BREAK
   5059                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x2e, temp1), rv);
   5060             SOC_IF_ERROR_BREAK
   5061                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x2f, temp2), rv);
   5062             break;
   5063 
   5064         case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK:
   5065             temp1 = 0;
   5066             value0 = COMPILER_64_LO(value);
   5067             if (value0 &  SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK) {
   5068                 temp1 |= 1U << 1;
   5069             }
   5070             if (value0 &  SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK) {
   5071                 temp1 |= 1U << 0;
   5072             }
   5073             SOC_IF_ERROR_BREAK
   5074                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x30, temp1), rv);
   5075             break;
   5076 
   5077         case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET:
   5078             value0 = COMPILER_64_LO(value);
   5079 
   5080             /* tx_timestamp_offset */
   5081             SOC_IF_ERROR_BREAK
   5082                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x15 + offset, (uint16)(value0 & 0xffff)), rv);
   5083 
   5084             if (offset < 4 ) {
   5085                 SOC_IF_ERROR_BREAK
   5086                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x63, 
   5087                         ((value0 & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv);
   5088             } else {
   5089                 uint16 offset1 = offset - 4;
   5090                 SOC_IF_ERROR_BREAK
   5091                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x64, 
   5092                         ((value0 & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv);
   5093             }
   5094             break;
   5095 
   5096         case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET:
   5097             value0 = COMPILER_64_LO(value);
   5098 
   5099             /* rx_timestamp_offset */
   5100             SOC_IF_ERROR_BREAK
   5101                 (_phy_54682e_blk_top_lvl_reg_write(unit, pc, 0, 0x1d + offset, (uint16)(value0 & 0xffff)), rv);
   5102 
   5103             if (offset < 4 ) {
   5104                 SOC_IF_ERROR_BREAK
   5105                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x65, 
   5106                         ((value0 & 0xf0000) >> ((4 - offset) << 2)), 0xf << (offset << 2)), rv);
   5107             } else {
   5108                 uint16 offset1 = offset - 4;
   5109                 SOC_IF_ERROR_BREAK
   5110                     (_phy_54682e_blk_top_lvl_reg_modify(unit, pc, 0, 0x66, 
   5111                         ((value0 & 0xf0000) >> ((4 - offset1) << 2)), 0xf << (offset1 << 2)), rv);
   5112             }
   5113             break;
   5114 
   5115         default:
   5116             return SOC_E_FAIL;
   5117         }
   5118     } while(0);
   5119 
   5120     pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   5121 
   5122     return SOC_E_NONE;
   5123 }
   5124 
   5125 STATIC int
   5126 phy_54682_timesync_control_get(int unit, soc_port_t port, soc_port_control_phy_timesync_t type, uint64 *value)
   5127 {
   5128     phy_ctrl_t *pc;
   5129     uint16 value0;
   5130     uint16 value1;
   5131     uint16 value2;
   5132     uint32 temp32;
   5133     int offset, rv = SOC_E_NONE;
   5134 
   5135     pc = EXT_PHY_SW_STATE(unit, port);
   5136 
   5137     offset = PHY54682_DEV_PHY_SLICE(pc);
   5138 
   5139     if ((!(PHY_IS_BCM54682E_OR_BCM54685E(pc) || PHY_IS_BCM54684E(pc))) || PHY_IS_BCM54682E_OR_BCM54685E_A0A1(pc)) {
   5140         return SOC_E_UNAVAIL;
   5141     }
   5142 
   5143     do {
   5144         /* pc->phy_id =  PHY54682_SLICE_ADDR(pc, 0); */
   5145         pc->phy_id =  PHY54682_DEV_PHY_ID_BASE(pc);
   5146 
   5147         switch (type) {
   5148         case SOC_PORT_CONTROL_PHY_TIMESYNC_HEARTBEAT_TIMESTAMP:
   5149             SOC_IF_ERROR_BREAK
   5150                 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x1), rv);
   5151 
   5152             SOC_IF_ERROR_BREAK
   5153                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x56, &value0), rv);
   5154             SOC_IF_ERROR_BREAK
   5155                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x57, &value1), rv);
   5156             SOC_IF_ERROR_BREAK
   5157                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x58, &value2), rv);
   5158 
   5159             SOC_IF_ERROR_BREAK
   5160                 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x2), rv);
   5161             SOC_IF_ERROR_BREAK
   5162                 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv);
   5163 
   5164             COMPILER_64_SET((*value), ((uint32)value2),  (((uint32)value1<<16)|((uint32)value0)));
   5165 
   5166         /*    *value =  (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */
   5167             break;
   5168 
   5169         case SOC_PORT_CONTROL_PHY_TIMESYNC_CAPTURE_TIMESTAMP:
   5170             SOC_IF_ERROR_BREAK
   5171                 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x4), rv);
   5172 
   5173             SOC_IF_ERROR_BREAK
   5174                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x53, &value0), rv);
   5175             SOC_IF_ERROR_BREAK
   5176                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x54, &value1), rv);
   5177             SOC_IF_ERROR_BREAK
   5178                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x55, &value2), rv);
   5179 
   5180             SOC_IF_ERROR_BREAK
   5181                 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x8), rv);
   5182             SOC_IF_ERROR_BREAK
   5183                 (WRITE_PHY54682_EXP_READ_START_END_CTRLr(unit, pc, 0x0), rv);
   5184 
   5185             COMPILER_64_SET((*value), ((uint32)value2),  (((uint32)value1<<16)|((uint32)value0)));
   5186 
   5187         /*   *value = (((uint64)value2) << 32) | (((uint64)value1) << 16) | ((uint64)value0); */
   5188             break;
   5189 
   5190         case SOC_PORT_CONTROL_PHY_TIMESYNC_NCOADDEND:
   5191             SOC_IF_ERROR_BREAK
   5192                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x44, &value0), rv);
   5193             /* *value = value0; */
   5194             COMPILER_64_SET((*value), 0,  (uint32)value0);
   5195             break;
   5196 
   5197         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOCAL_TIME:
   5198             SOC_IF_ERROR_BREAK
   5199                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x45, &value0), rv);
   5200             SOC_IF_ERROR_BREAK
   5201                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x46, &value1), rv);
   5202             SOC_IF_ERROR_BREAK
   5203                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x47, &value2), rv);
   5204 
   5205             COMPILER_64_SET((*value), (value2 & 0x0fff), ((uint32)value1 << 16) | value0 );
   5206             COMPILER_64_SHL((*value), 4);
   5207             break;
   5208 
   5209         case SOC_PORT_CONTROL_PHY_TIMESYNC_LOAD_CONTROL:
   5210             SOC_IF_ERROR_BREAK
   5211                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x2e, &value1), rv);
   5212             SOC_IF_ERROR_BREAK
   5213                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x2f, &value2), rv);
   5214             value0 = 0;
   5215             if (value1 & (1U << 11)) {
   5216                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_LOAD;
   5217             }
   5218             if (value2 & (1U << 11)) {
   5219                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TN_ALWAYS_LOAD;
   5220             }
   5221             if (value1 & (1U << 10)) {
   5222                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_LOAD;
   5223             }
   5224             if (value2 & (1U << 10)) {
   5225                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_TIMECODE_ALWAYS_LOAD;
   5226             }
   5227             if (value1 & (1U << 9)) {
   5228                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_LOAD;
   5229             }
   5230             if (value2 & (1U << 9)) {
   5231                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_SYNCOUT_ALWAYS_LOAD;
   5232             }
   5233             if (value1 & (1U << 8)) {
   5234                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_LOAD;
   5235             }
   5236             if (value1 & (1U << 8)) {
   5237                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_DIVIDER_ALWAYS_LOAD;
   5238             }
   5239             if (value1 & (1U << 7)) {
   5240                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_LOAD;
   5241             }
   5242             if (value1 & (1U << 7)) {
   5243                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_LOCAL_TIME_ALWAYS_LOAD;
   5244             }
   5245             if (value1 & (1U << 6)) {
   5246                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_LOAD;
   5247             }
   5248             if (value2 & (1U << 6)) {
   5249                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_NCO_ADDEND_ALWAYS_LOAD;
   5250             }
   5251             if (value1 & (1U << 5)) {
   5252                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_LOAD;
   5253             }
   5254             if (value2 & (1U << 5)) {
   5255                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_LOOP_FILTER_ALWAYS_LOAD;
   5256             }
   5257             if (value1 & (1U << 4)) {
   5258                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_LOAD;
   5259             }
   5260             if (value2 & (1U << 4)) {
   5261                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_ALWAYS_LOAD;
   5262             }
   5263             if (value1 & (1U << 3)) {
   5264                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_LOAD;
   5265             }
   5266             if (value2 & (1U << 3)) {
   5267                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_REF_PHASE_DELTA_ALWAYS_LOAD;
   5268             }
   5269             if (value1 & (1U << 2)) {
   5270                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_LOAD;
   5271             }
   5272             if (value2 & (1U << 2)) {
   5273                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K3_ALWAYS_LOAD;
   5274             }
   5275             if (value1 & (1U << 1)) {
   5276                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_LOAD;
   5277             }
   5278             if (value2 & (1U << 1)) {
   5279                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K2_ALWAYS_LOAD;
   5280             }
   5281             if (value1 & (1U << 0)) {
   5282                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_LOAD;
   5283             }
   5284             if (value2 & (1U << 0)) {
   5285                 value0 |= (uint16) SOC_PORT_PHY_TIMESYNC_DPLL_K1_ALWAYS_LOAD;
   5286             }
   5287             COMPILER_64_SET((*value), 0, (uint32)value0);
   5288             break;
   5289 
   5290         case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT:
   5291             SOC_IF_ERROR_BREAK
   5292                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x31, &value1), rv);
   5293             value0 = 0;
   5294             if (value1 & (1U << 1)) {
   5295                 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT;
   5296             }
   5297             if (value1 & (1U << 0)) {
   5298                 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT;
   5299             }
   5300             COMPILER_64_SET((*value), 0, (uint32)value0);
   5301             break;
   5302 
   5303         case SOC_PORT_CONTROL_PHY_TIMESYNC_INTERRUPT_MASK:
   5304             SOC_IF_ERROR_BREAK
   5305                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x30, &value1), rv);
   5306             value0 = 0;
   5307             if (value1 & (1U << 1)) {
   5308                 value0 |= SOC_PORT_PHY_TIMESYNC_TIMESTAMP_INTERRUPT_MASK;
   5309             }
   5310             if (value1 & (1U << 0)) {
   5311                 value0 |= SOC_PORT_PHY_TIMESYNC_FRAMESYNC_INTERRUPT_MASK;
   5312             }
   5313             COMPILER_64_SET((*value), 0, (uint32)value0);
   5314             break;
   5315 
   5316         case SOC_PORT_CONTROL_PHY_TIMESYNC_TX_TIMESTAMP_OFFSET:
   5317         /* tx_timestamp_offset */
   5318             SOC_IF_ERROR_BREAK
   5319                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x15 + offset, &value1), rv);
   5320             if (offset < 4 ) {
   5321                 SOC_IF_ERROR_BREAK
   5322                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x63, &value2), rv);
   5323                 temp32 = (value2 & (0xf << (offset << 2))) << ((4 - offset) << 2);
   5324             } else {
   5325                 uint16 offset1 = offset - 4;
   5326                 SOC_IF_ERROR_BREAK
   5327                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x64, &value2), rv);
   5328                 temp32 = (value2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2);
   5329             }
   5330             /* *value = temp32 | value1; */
   5331             COMPILER_64_SET((*value), 0, (uint32)(temp32 | value1));
   5332             break;
   5333 
   5334         case SOC_PORT_CONTROL_PHY_TIMESYNC_RX_TIMESTAMP_OFFSET:
   5335         /* rx_timestamp_offset */
   5336             SOC_IF_ERROR_BREAK
   5337                 (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x1d + offset, &value1), rv);
   5338             if (offset < 4 ) {
   5339                 SOC_IF_ERROR_BREAK
   5340                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x65, &value2), rv);
   5341                 temp32 = (value2 & (0xf << (offset << 2))) << ((4 - offset) << 2);
   5342             } else {
   5343                 uint16 offset1 = offset - 4;
   5344                 SOC_IF_ERROR_BREAK
   5345                     (_phy_54682e_blk_top_lvl_reg_read(unit, pc, 0, 0x66, &value2), rv);
   5346                 temp32 = (value2 & (0xf << (offset1 << 2))) << ((4 - offset1) << 2);
   5347             }
   5348             /* *value = temp32 | value1; */
   5349             COMPILER_64_SET((*value), 0, (uint32)(temp32 | value1));
   5350             break;
   5351 
   5352         default:
   5353             return SOC_E_FAIL;
   5354         }
   5355     } while(0);
   5356 
   5357     pc->phy_id =  PHY54682_DEV_PHY_ID_ORIG(pc);
   5358 
   5359     return SOC_E_NONE;
   5360 }
   5361 
   5362 #ifdef BROADCOM_DEBUG
   5363 
   5364 /*
   5365  * Function:
   5366  *      phy_54682_shadow_dump
   5367  * Purpose:
   5368  *      Debug routine to dump all shadow registers.
   5369  * Parameters:
   5370  *      unit - StrataSwitch unit #.
   5371  *      port - StrataSwitch port #.
   5372  */
   5373 
   5374 void
   5375 phy_54682_shadow_dump(int unit, soc_port_t port)
   5376 {
   5377     phy_ctrl_t *pc;
   5378     uint16      tmp;
   5379     int         i;
   5380 
   5381     pc       = EXT_PHY_SW_STATE(unit, port);
   5382 
   5383     /* Register 0x18 Shadows */
   5384     for (i = 0; i <= 7; i++) {
   5385         WRITE_PHY_REG(unit, pc, 0x18, (i << 12) | 0x7);
   5386         READ_PHY_REG(unit, pc, 0x18, &tmp);
   5387         if ((tmp & ~7) == 0x0000) {
   5388             continue;
   5389         }
   5390         LOG_CLI((BSL_META_U(unit, "0x18[0x%x]=0x%04x\n"), i, tmp));
   5391     }
   5392 
   5393     /* Register 0x1c Shadows */
   5394     for (i = 0; i <= 0x1f; i++) {
   5395         WRITE_PHY_REG(unit, pc, 0x1c, i << 10);
   5396         READ_PHY_REG(unit, pc, 0x1c, &tmp);
   5397         if ((tmp & ~0x7c00) == 0x0000) {
   5398             continue;
   5399         }
   5400         LOG_CLI((BSL_META_U(unit, "0x1c[0x%x]=0x%04x\n"), i, tmp));
   5401     }
   5402 
   5403     /* Register 0x17/0x15 Shadows */
   5404     for (i = 0; i <= 0x13; i++) {
   5405         WRITE_PHY_REG(unit, pc, 0x17, 0xf00 | i);
   5406         READ_PHY_REG(unit, pc, 0x15, &tmp);
   5407         if (tmp  == 0x0000) {
   5408             continue;
   5409         }
   5410         LOG_CLI((BSL_META_U(unit,"0x17[0x%x]=0x%04x\n"), i, tmp));
   5411     }
   5412 }
   5413 
   5414 #endif /* BROADCOM_DEBUG */
   5415 
   5416 STATIC int
   5417 _phy_54682_tx_control_set(int unit, soc_port_t port,
   5418                                  soc_phy_control_t type, uint32 value)
   5419 {
   5420     phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port);
   5421     uint16      data;
   5422     int         qsgmii_port;
   5423     uint32      qsgmii_aer_reg;
   5424 
   5425     /* Support only system side - for now */
   5426     if(!(pc->flags & PHYCTRL_SYS_SIDE_CTRL)) {
   5427         return SOC_E_UNAVAIL;
   5428     }
   5429 
   5430     qsgmii_port = ((PHY54682_DEV_PHY_SLICE(pc)) < 4) ? 0 : 1;
   5431     qsgmii_aer_reg = (_phy_54682_qsgmii_aer[qsgmii_port] << 16) | 0x8067;
   5432     data = (uint16) (value & 0xf);
   5433 
   5434     switch( type ) {
   5435         case SOC_PHY_CONTROL_PREEMPHASIS:
   5436             pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc);
   5437             data <<= 12;
   5438             SOC_IF_ERROR_RETURN
   5439                    (phy_reg_aer_modify(unit, pc, qsgmii_aer_reg, data, 0xf000));
   5440             pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc);
   5441             break;
   5442 
   5443         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   5444             pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc);
   5445             data <<= 8;
   5446             SOC_IF_ERROR_RETURN
   5447                    (phy_reg_aer_modify(unit, pc, qsgmii_aer_reg, data, 0x0f00));
   5448             pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc);
   5449             break;
   5450 
   5451         default:
   5452             return SOC_E_PARAM;
   5453     }
   5454 
   5455     return SOC_E_NONE;
   5456 }
   5457 
   5458 STATIC int
   5459 _phy_54682_tx_control_get(int unit, soc_port_t port,
   5460                                  soc_phy_control_t type, uint32 *value)
   5461 {
   5462     phy_ctrl_t    *pc = EXT_PHY_SW_STATE(unit, port);
   5463     uint16 data;
   5464     int qsgmii_port;
   5465     uint32 qsgmii_aer_reg;
   5466 
   5467     /* Support only system side - for now */
   5468     if(!(pc->flags & PHYCTRL_SYS_SIDE_CTRL)) {
   5469         return SOC_E_UNAVAIL;
   5470     }
   5471 
   5472     qsgmii_port = ((PHY54682_DEV_PHY_SLICE(pc)) < 4) ? 0 : 1;
   5473     qsgmii_aer_reg = (_phy_54682_qsgmii_aer[qsgmii_port] << 16) | 0x8067;
   5474     
   5475     data = 0;
   5476 
   5477     switch(type) {
   5478         case SOC_PHY_CONTROL_PREEMPHASIS:
   5479             pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc);
   5480             SOC_IF_ERROR_RETURN   
   5481                (phy_reg_aer_read(unit, pc, qsgmii_aer_reg, &data));
   5482             *value = (data & 0xf000) >> 12;
   5483             pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc);
   5484             break;
   5485         case SOC_PHY_CONTROL_DRIVER_CURRENT:
   5486             pc->phy_id = PHY_BCM54682_QSGMII_DEV_ADDR(pc);
   5487             SOC_IF_ERROR_RETURN   
   5488                (phy_reg_aer_read(unit, pc, qsgmii_aer_reg, &data));
   5489             *value = (data & 0x0f00) >> 8;
   5490             pc->phy_id = PHY54682_DEV_PHY_ID_ORIG(pc);
   5491             break;
   5492         default:
   5493             return SOC_E_PARAM;
   5494     }
   5495 
   5496     return SOC_E_NONE;
   5497 }
   5498 
   5499 /*
   5500  * Variable:    phy_54682drv_ge
   5501  * Purpose:     PHY driver for 54682
   5502  */
   5503 
   5504 phy_driver_t phy_54682drv_ge = {
   5505     "54682 Gigabit PHY Driver",
   5506     phy_54682_init,
   5507     phy_fe_ge_reset,
   5508     phy_54682_link_get,
   5509     phy_54682_enable_set,
   5510     phy_54682_enable_get,
   5511     phy_54682_duplex_set,
   5512     phy_54682_duplex_get,
   5513     phy_54682_speed_set,
   5514     phy_54682_speed_get,
   5515     phy_54682_master_set,
   5516     phy_54682_master_get,
   5517     phy_54682_autoneg_set,
   5518     phy_54682_autoneg_get,
   5519     NULL,
   5520     NULL,
   5521     NULL,
   5522     phy_54682_lb_set,
   5523     phy_54682_lb_get,
   5524     phy_54682_interface_set,
   5525     phy_54682_interface_get,
   5526     NULL,
   5527     phy_54682_link_up,           /* Phy link up event */
   5528     phy_54682_link_down,         /* Phy link down event */
   5529     phy_54682_mdix_set,
   5530     phy_54682_mdix_get,
   5531     phy_54682_mdix_status_get,
   5532     phy_54682_medium_config_set,
   5533     phy_54682_medium_config_get,
   5534     phy_54682_medium_status,
   5535     phy54682_cable_diag_dispatch,
   5536     NULL,                       /* phy_link_change */
   5537     phy_54682_control_set,      /* phy_control_set */ 
   5538     phy_54682_control_get,      /* phy_control_get */
   5539     phy_ge_reg_read,
   5540     phy_ge_reg_write,
   5541     phy_ge_reg_modify,
   5542     NULL,                        /* Phy event notify */ 
   5543     phy_54682_probe,                        /* pd_probe */
   5544     phy_54682_ability_advert_set,
   5545     phy_54682_ability_advert_get,
   5546     phy_54682_ability_remote_get,
   5547     phy_54682_ability_local_get,
   5548     NULL,                       /* f/w set */
   5549     phy_54682_timesync_config_set,
   5550     phy_54682_timesync_config_get,
   5551     phy_54682_timesync_control_set,
   5552     phy_54682_timesync_control_get
   5553 
   5554 };
   5555 #else /* INCLUDE_PHY_54682 */
   5556 int _soc_phy_54682_not_empty;
   5557 #endif /* INCLUDE_PHY_54682 */
   5558