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

phy8706.c (144983B)


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