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

phy8750.c (61509B)


      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:        phy8750.c
      9  * Purpose:    Phys Driver support for Broadcom 8750 Serial 10Gig
     10  *             transceiver :XFI system side and SFI Line interface.
     11  * Note:       
     12  */
     13 
     14 #include <sal/types.h>
     15 #include <shared/bsl.h>
     16 #include <soc/drv.h>
     17 #include <soc/debug.h>
     18 #include <soc/error.h>
     19 #include <soc/phyreg.h>
     20 
     21 #include <soc/phy.h>
     22 #include <soc/phy/phyctrl.h>
     23 #include <soc/phy/drv.h>
     24 
     25 #include "phydefs.h"      /* Must include before other phy related includes */
     26 
     27 #if defined(INCLUDE_PHY_8750)
     28 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     29 #include "phyident.h"
     30 #include "phyreg.h"
     31 #include "phynull.h"
     32 #include "phyxehg.h"
     33 #include "phy8750.h"
     34 /*
     35  * SPI-ROM Program related defs
     36  */
     37 #define SPI_CTRL_1_L        0xC000
     38 #define SPI_CTRL_1_H        0xC002
     39 #define SPI_CTRL_2_L        0xC400
     40 #define SPI_CTRL_2_H        0xC402
     41 #define SPI_TXFIFO          0xD000
     42 #define SPI_RXFIFO          0xD400
     43 #define WR_CPU_CTRL_REGS    0x11
     44 #define RD_CPU_CTRL_REGS    0xEE
     45 #define WR_CPU_CTRL_FIFO    0x66
     46 
     47 /*
     48  * SPI Controller Commands(Messages).
     49  */
     50 #define MSGTYPE_HWR          0x40
     51 #define MSGTYPE_HRD          0x80
     52 #define WRSR_OPCODE          0x01
     53 #define WR_OPCODE            0x02
     54 #define WRDI_OPCODE          0x04
     55 #define RDSR_OPCODE          0x05
     56 #define WREN_OPCODE          0x06
     57 #define WR_BLOCK_SIZE        0x40
     58 #define TOTAL_WR_BYTE        0x4000
     59                                                                                 
     60 #define WR_TIMEOUT   1000000
     61 
     62 /* typedefs */
     63 typedef struct {
     64     int rx_los;
     65     int rx_los_invert;
     66     int mod_abs;
     67     int mod_abs_invert;
     68 } PHY8750_DEV_DESC_t;
     69 
     70 /* device field macros */
     71 #define RX_LOS(_pc) (((PHY8750_DEV_DESC_t *)((_pc) + 1))->rx_los)
     72 #define RX_LOS_INVERT(_pc) (((PHY8750_DEV_DESC_t *)((_pc) + 1))->rx_los_invert)
     73 #define MOD_ABS(_pc) (((PHY8750_DEV_DESC_t *)((_pc) + 1))->mod_abs)
     74 #define MOD_ABS_INVERT(_pc) (((PHY8750_DEV_DESC_t *)((_pc) + 1))->mod_abs_invert)
     75 
     76 static int write_message(int unit, phy_ctrl_t *pc, uint16 wrdata, 
     77                          uint16 *rddata);
     78                                                                                 
     79 
     80 STATIC int _phy8754_mdio_firmware_download(int unit, int port, int offset, uint8 *array,int datalen);
     81 STATIC int phy_8750_speed_get(int, soc_port_t, int *);
     82 
     83 extern unsigned char phy8754_ucode_bin[];
     84 extern unsigned int phy8754_ucode_bin_len;
     85 
     86 
     87 STATIC int
     88 _phy8750_optical_sig_cfg(int unit, int port)
     89 {
     90     uint16 mask16;
     91     uint16 data16;
     92     phy_ctrl_t     *pc;
     93 
     94     pc = EXT_PHY_SW_STATE(unit, port);
     95 
     96     mask16 = PHY8750_RXLOS_OVERRIDE_MASK |
     97              PHY8750_MOD_ABS_OVERRIDE_MASK;
     98     data16 = 0;
     99     /* default: override RX_LOS signalling */
    100     if (!RX_LOS(pc)) {
    101         data16 |= PHY8750_RXLOS_OVERRIDE_MASK;
    102     }
    103     /* default: override MOD_ABS signalling */
    104     if (!MOD_ABS(pc)) {
    105         data16 |= PHY8750_MOD_ABS_OVERRIDE_MASK;
    106     }
    107 
    108     SOC_IF_ERROR_RETURN
    109        (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit,pc,
    110            PHY8750_PMAD_OPTICAL_CFG_REG, data16,mask16));
    111 
    112     mask16 = PHY8750_RXLOS_LVL_MASK | PHY8750_MOD_ABS_LVL_MASK;
    113     data16 = 0;
    114     /* default: RX_LOS level high */
    115     if (!RX_LOS_INVERT(pc)) {
    116         data16 |= PHY8750_RXLOS_LVL_MASK;
    117     }
    118     /* default: MOD_ABS level high */
    119     if (!MOD_ABS_INVERT(pc)) {
    120         data16 |= PHY8750_MOD_ABS_LVL_MASK;
    121     }
    122     SOC_IF_ERROR_RETURN
    123        (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit,pc,
    124                  PHY8750_PMAD_OPTICAL_SIG_LVL_REG,
    125                  data16, mask16));
    126     return SOC_E_NONE;
    127 }
    128 
    129 STATIC int
    130 _phy8754_rom_load(int unit, int port, phy_ctrl_t *pc)
    131 {
    132 
    133     uint8 phy_id, i;
    134 
    135     SOC_IF_ERROR_RETURN
    136         (_phy8750_optical_sig_cfg(unit,port));
    137 
    138     phy_id = pc->phy_id;
    139     /* configure all four ports  */
    140     for (i = 0; i < 4; i++) {
    141         pc->phy_id = (phy_id | 0x3) & ~i; /* Port 3, 2, 1 and 0 */
    142 
    143         /* Disable all port's SPI. bits 3:0 is GPIO port = input.
    144          * SPI control and debug port pin is multiplexed 
    145          */
    146         SOC_IF_ERROR_RETURN
    147             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC843, 0x000F));
    148 
    149         /* bits 3:2 is Mode control for SPI/Debug/GPIO pins */
    150         SOC_IF_ERROR_RETURN
    151             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC840, 0x000C));
    152 
    153         /* Set bit SPI Download (15), SER Boot (14) And SPI Port Enable (0):
    154          * enable SPI bus arbitor.
    155          */
    156         SOC_IF_ERROR_RETURN
    157             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC848, 0xC0F1));
    158 
    159     }
    160     /* restore the original phy_id */
    161     pc->phy_id = phy_id;
    162 
    163     /* place the port's uC in reset state */
    164     SOC_IF_ERROR_RETURN
    165         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA10, 0x018F));
    166 
    167     SOC_IF_ERROR_RETURN
    168         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC843, 0x0000));
    169     SOC_IF_ERROR_RETURN
    170         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC840, 0x0000));
    171     SOC_IF_ERROR_RETURN
    172         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA10, 0x0188));
    173 
    174     sal_usleep(100000); /* Sleep for at least 80ms */
    175 
    176     SOC_IF_ERROR_RETURN
    177         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC843, 0x000F));
    178     SOC_IF_ERROR_RETURN
    179         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC840, 0x000C));
    180 
    181     return SOC_E_NONE;
    182 }
    183 
    184 STATIC int
    185 _phy8750_rom_load(int unit, int port, phy_ctrl_t *pc)
    186 {
    187     uint16 data = 0;
    188 
    189     /* Read Chip IDs */
    190     SOC_IF_ERROR_RETURN
    191         (READ_PHY8750_PMA_PMD_CHIPIDr(unit, pc, &data));
    192     if (data == 0x8754) {
    193         SOC_IF_ERROR_RETURN
    194             (_phy8754_rom_load(unit, port, pc));
    195     } else {
    196         SOC_IF_ERROR_RETURN(
    197             READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xc848, &data));
    198         data |= 0xc000; /* Set SER boot and download via SPI */
    199         SOC_IF_ERROR_RETURN(
    200             WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xc848, data));
    201 
    202         /* Reset */;
    203         SOC_IF_ERROR_RETURN(
    204             MODIFY_PHY8750_PMA_PMD_CTRLr(unit, pc, 0x8000, 0x8000));
    205     }
    206 
    207     /* Wait for atleast 100ms for code to download via SPI port*/
    208     sal_usleep(200000);
    209 
    210     return SOC_E_NONE;
    211 }
    212 
    213 
    214 
    215 STATIC int
    216 _phy8750_adjust_xfi_tx_preemphasis(int unit, int port, phy_ctrl_t *pc)
    217 {
    218 
    219     SOC_IF_ERROR_RETURN(
    220         PHY8750_XFI(unit, pc));
    221 
    222     SOC_IF_ERROR_RETURN(
    223         WRITE_PHY8750_XFI_PMA_PMD_REG(unit, pc, 0xc90b, 0xb000));
    224 
    225     SOC_IF_ERROR_RETURN(
    226         WRITE_PHY8750_XFI_PMA_PMD_REG(unit, pc, 0xc90c, 0x1052));
    227 
    228     SOC_IF_ERROR_RETURN(
    229         WRITE_PHY8750_XFI_PMA_PMD_REG(unit, pc, 0xc900, 0xec91));
    230 
    231     SOC_IF_ERROR_RETURN(
    232         PHY8750_MMF(unit, pc));
    233 
    234     return SOC_E_NONE;
    235 }
    236 
    237 /* Function:
    238  *    phy_8750_init
    239  * Purpose:    
    240  *    Initialize 8750 phys
    241  * Parameters:
    242  *    unit - StrataSwitch unit #.
    243  *    port - StrataSwitch port #. 
    244  * Returns:    
    245  *    SOC_E_NONE
    246  */
    247 
    248 STATIC int
    249 phy_8750_init(int unit, soc_port_t port)
    250 {
    251     soc_timeout_t  to;
    252     int            rv = SOC_E_NONE;
    253     uint16         data16,ucode_ver;
    254     phy_ctrl_t     *pc;
    255     uint32         phy_ext_rom_boot, phy_long_xfi; 
    256     uint16         chip_id = 0xffff, chip_rev = 0xffff;
    257 
    258     pc = EXT_PHY_SW_STATE(unit, port);
    259     
    260     PHY_FLAGS_SET(unit, port,  PHY_FLAGS_FIBER | PHY_FLAGS_C45);
    261 
    262 
    263     /* Read Chip IDs */
    264     SOC_IF_ERROR_RETURN
    265         (READ_PHY8750_PMA_PMD_CHIPIDr(unit, pc, &chip_id));
    266     /* Read Chip Revision */
    267     SOC_IF_ERROR_RETURN
    268         (READ_PHY8750_PMA_PMD_CHIPREVr(unit, pc, &chip_rev));
    269     chip_rev &= 0x000f;
    270 
    271 
    272     /* Support BCM8750, BCM8752 and BCM8754 PHYs */
    273     if ((chip_id != 0x8750) && (chip_id != 0x8752) && (chip_id != 0x8754)) {
    274         LOG_CLI((BSL_META_U(unit,
    275                             "Unsupported PHY: Chip Id = %x\n"), chip_id)); 
    276         return SOC_E_FAIL;
    277     }
    278 
    279     if (chip_id == 0x8754) {
    280         /* These two register writes allow the device boots and stays executing from
    281          * the internal ROM after the PMA/PMD MII_CTRL_RESET. Otherwise it will load
    282          * the content from SPI-ROM to RAM and executes from the RAM. In case the
    283          * SPI-ROM has not been programmed with any firmware, the uController will
    284          * not work properly.
    285          */  
    286         SOC_IF_ERROR_RETURN
    287             (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC848, 0, (1 << 14) |(1 << 13)));
    288         SOC_IF_ERROR_RETURN
    289             (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xca85, 0, 1 ));
    290     }
    291      
    292     /* Reset the device */
    293     SOC_IF_ERROR_RETURN
    294         (MODIFY_PHY8750_PMA_PMD_CTRLr(unit, pc,
    295                                       MII_CTRL_RESET, MII_CTRL_RESET));
    296     SOC_IF_ERROR_RETURN
    297         (MODIFY_PHY8750_PCS_CTRLr(unit, pc,
    298                                   MII_CTRL_RESET, MII_CTRL_RESET));
    299 
    300     /* Wait for device to come out of reset */
    301     soc_timeout_init(&to, 10000, 0);
    302     while (!soc_timeout_check(&to)) {
    303         rv = READ_PHY8750_PMA_PMD_CTRLr(unit, pc, &data16);
    304         if (((data16 & MII_CTRL_RESET) == 0) ||
    305             SOC_FAILURE(rv)) {
    306             break;
    307         }
    308     }
    309     if (((data16 & MII_CTRL_RESET) != 0) || SOC_FAILURE(rv)) {
    310         LOG_WARN(BSL_LS_SOC_PHY,
    311                  (BSL_META_U(unit,
    312                              "PHY8750/8726 reset failed: u=%d p=%d\n"),
    313                   unit, port));
    314         return SOC_E_FAIL;
    315     }
    316 
    317     /* check optical signaling configuration */
    318     RX_LOS(pc) = soc_property_port_get(unit, port,spn_PHY_RX_LOS, 0);
    319     MOD_ABS(pc) = soc_property_port_get(unit, port,spn_PHY_MOD_ABS, 0);
    320     RX_LOS_INVERT(pc) = soc_property_port_get(unit, port,spn_PHY_RX_LOS_INVERT, 0);
    321     MOD_ABS_INVERT(pc) = soc_property_port_get(unit, port,spn_PHY_MOD_ABS_INVERT, 0);
    322 
    323     phy_ext_rom_boot = soc_property_port_get(unit, port, 
    324                                             spn_PHY_EXT_ROM_BOOT, 1);
    325     if (phy_ext_rom_boot) {
    326         SOC_IF_ERROR_RETURN
    327             (_phy8750_rom_load(unit, port, pc));
    328     } else {
    329         /* MDIO loading */
    330         if (chip_id == 0x8754) {
    331             SOC_IF_ERROR_RETURN
    332                 (_phy8754_mdio_firmware_download(unit, port, 0,phy8754_ucode_bin,
    333                                         phy8754_ucode_bin_len));
    334             SOC_IF_ERROR_RETURN
    335                 (_phy8750_optical_sig_cfg(unit,port));
    336         }
    337     }
    338 
    339     /* read the microcode revision */
    340     SOC_IF_ERROR_RETURN
    341         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA1A, &ucode_ver));
    342  
    343     /* If microcode revision >  0x0301, then check the completion of 
    344      * the SPI-ROM load.
    345      */
    346     if (ucode_ver >= 0x0301) {
    347         rv = READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA1C, &data16);
    348         if (data16 != 0x600D || SOC_FAILURE(rv)) {
    349             LOG_WARN(BSL_LS_SOC_PHY,
    350                      (BSL_META_U(unit,
    351                                  "8750: p=%d SPI-ROM load: Bad Checksum (0x%x)\n"),
    352                                  port, data16));
    353              /* let it continue in case a blank SPI-ROM or allow other ports to 
    354               * initialize. Internal ROM code always show checksum as zero. 
    355               */
    356         }
    357     } else {
    358         LOG_WARN(BSL_LS_SOC_PHY,
    359                  (BSL_META_U(unit,
    360                              "8750: p=%d SPI-ROM load: Invalid Ucode version (0x%x)\n"),
    361                              port, ucode_ver));
    362              /* let it continue to allow other ports to initialize */
    363     }
    364 
    365     LOG_INFO(BSL_LS_SOC_PHY,
    366              (BSL_META_U(unit,
    367                          "8750: u=%d port%d rom code ver: 0x%x: init.\n"),
    368                          unit, port, ucode_ver));
    369 
    370     /* By default XFI cannot drive long distance cables. TX premphasis needs
    371      * to be adjusted if long cables are used on the XFI side
    372      */
    373     phy_long_xfi = soc_property_port_get(unit, port, 
    374                                          spn_PHY_LONG_XFI, 1);
    375     if (phy_long_xfi) {
    376         SOC_IF_ERROR_RETURN(
    377             _phy8750_adjust_xfi_tx_preemphasis(unit, port, pc));
    378     }
    379 
    380     /* Disable SyncE */
    381     SOC_IF_ERROR_RETURN(
    382         PHY8750_MMF(unit, pc));
    383     SOC_IF_ERROR_RETURN(
    384         MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xc840, 0x0000, 0xffff));
    385     SOC_IF_ERROR_RETURN(
    386         MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xcd17, 0x0000, 0xffff));
    387     SOC_IF_ERROR_RETURN(
    388         PHY8750_XFI(unit, pc));
    389     SOC_IF_ERROR_RETURN(
    390         MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xcd17, 0x0000, 0xffff));
    391     SOC_IF_ERROR_RETURN(
    392         PHY8750_MMF(unit, pc));
    393     SOC_IF_ERROR_RETURN(
    394         MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
    395           PHY8750_PMAD_OPTICAL_CFG_REG, (1U<<12), ((1U<<12) | (1U<<4))));
    396 
    397     LOG_CLI((BSL_META_U(unit,
    398                         "BCM%x (Rev. %d): u=%d port%d rom code ver. 0x%x\n"),
    399              chip_id, chip_rev, unit, port, ucode_ver));
    400 
    401     return SOC_E_NONE;
    402 }
    403 
    404 /*
    405  * Function:
    406  *      phy_8750_an_get
    407  * Purpose:
    408  *      Get the current auto-negotiation status (enabled/busy)
    409  * Parameters:
    410  *      unit - StrataSwitch unit #.
    411  *      port - StrataSwitch port #.
    412  *      an   - (OUT) if true, auto-negotiation is enabled.
    413  *      an_done - (OUT) if true, auto-negotiation is complete. This
    414  *              value is undefined if an == false.
    415  * Returns:
    416  *      SOC_E_XXX
    417  */
    418 
    419 STATIC int
    420 phy_8750_an_get(int unit, soc_port_t port, int *an, int *an_done)
    421 {
    422     phy_ctrl_t *pc;
    423     uint16 an_status;
    424 
    425     pc = EXT_PHY_SW_STATE(unit, port);
    426     SOC_IF_ERROR_RETURN
    427         (READ_PHY8750_MMF_AN_REG(unit, pc, 0xFFE0, &an_status));
    428     *an = (an_status & PHY8750_AN_ENABLE)? TRUE: FALSE;
    429 
    430     SOC_IF_ERROR_RETURN
    431         (READ_PHY8750_MMF_AN_REG(unit, pc, 0xFFE1, &an_status));
    432     *an_done = (an_status & PHY8750_AN_DONE)? TRUE: FALSE;
    433 
    434     return SOC_E_NONE;
    435 }
    436 
    437 /*
    438  * Function:
    439  *      phy_8750_an_set
    440  * Purpose:
    441  *      Enable or disabled auto-negotiation on the specified port.
    442  * Parameters:
    443  *      unit - StrataSwitch unit #.
    444  *      port - StrataSwitch port #.
    445  *      an   - Boolean, if true, auto-negotiation is enabled
    446  *              (and/or restarted). If false, autonegotiation is disabled.
    447  * Returns:
    448  *      SOC_E_XXX
    449  */
    450 STATIC int
    451 phy_8750_an_set(int unit, soc_port_t port, int an)
    452 {
    453     phy_ctrl_t  *pc;
    454     phy_ctrl_t  *int_pc;
    455 
    456     int_pc = INT_PHY_SW_STATE(unit, port);
    457     if (NULL != int_pc) {
    458         SOC_IF_ERROR_RETURN(
    459         PHY_AUTO_NEGOTIATE_SET(int_pc->pd, unit, port, an));
    460     }
    461 
    462     pc = EXT_PHY_SW_STATE(unit, port);
    463 
    464     LOG_INFO(BSL_LS_SOC_PHY,
    465              (BSL_META_U(unit,
    466                          "phy_8750_an_set: u=%d p=%d an=%d\n"),
    467                          unit, port, an));
    468 
    469     if (an) {
    470         /* Clear Forced Speed selections in Miscellaneous 2 Register */
    471         SOC_IF_ERROR_RETURN
    472             (WRITE_PHY8750_MMF_AN_REG(unit, pc, 0x8309, 0x0000));
    473         /* Enable Clause 37 AN */
    474         SOC_IF_ERROR_RETURN
    475             (WRITE_PHY8750_MMF_AN_REG(unit, pc, 0xFFE0, 0x1300));
    476     } else {
    477         /* disable Clause 37 AN */
    478         SOC_IF_ERROR_RETURN
    479             (WRITE_PHY8750_MMF_AN_REG(unit, pc, 0xFFE0, 0));
    480         SOC_IF_ERROR_RETURN
    481             (WRITE_PHY8750_MMF_AN_REG(unit, pc, 0x8309, 0x0020));
    482     }
    483 
    484     return SOC_E_NONE;
    485 }
    486 
    487 /*
    488  * Function:
    489  *      phy_8750_ability_advert_get
    490  * Purpose:
    491  *      Get the current advertisement for auto-negotiation.
    492  * Parameters:
    493  *      unit - StrataSwitch unit #.
    494  *      port - StrataSwitch port #.
    495  *      mode - (OUT) Port mode mask indicating supported options/speeds.
    496  * Returns:
    497  *      SOC_E_XXX
    498  * Notes:
    499  *      The advertisement is retrieved for the ACTIVE medium.
    500  *      No synchronization performed at this level.
    501  */
    502 
    503 STATIC int
    504 phy_8750_ability_advert_get(int unit, soc_port_t port,
    505                            soc_port_ability_t *ability)
    506 {
    507     uint16           an_adv;
    508     soc_port_mode_t  mode;
    509     phy_ctrl_t      *pc;
    510 
    511     if (NULL == ability) {
    512         return (SOC_E_PARAM);
    513     }
    514     pc = EXT_PHY_SW_STATE(unit, port);
    515 
    516     SOC_IF_ERROR_RETURN
    517         (READ_PHY8750_MMF_AN_REG(unit, pc, 0xFFE0, &an_adv));
    518 
    519     mode = 0;
    520     mode |= (an_adv & 0x1000) ? SOC_PA_SPEED_1000MB : 0;
    521 
    522     /* check Full Duplex advertisement on Clause 37 */
    523     SOC_IF_ERROR_RETURN
    524         (READ_PHY8750_MMF_AN_REG(unit, pc, 0xFFE4, &an_adv));
    525     mode |= (an_adv & MII_ANA_C37_FD) ? SOC_PA_SPEED_1000MB : 0;
    526 
    527     ability->speed_full_duplex = mode;
    528     ability->pause = 0;
    529 
    530     switch (an_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) {
    531         case MII_ANA_C37_PAUSE:
    532             ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
    533             break;
    534         case MII_ANA_C37_ASYM_PAUSE:
    535             ability->pause = SOC_PA_PAUSE_TX;
    536             break;
    537         case MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE:
    538             ability->pause = SOC_PA_PAUSE_RX;
    539             break;
    540     }
    541 
    542     LOG_INFO(BSL_LS_SOC_PHY,
    543              (BSL_META_U(unit,
    544                          "phy_8750_ability_advert_get: u=%d p=%d speed(FD)=0x%x pause=0x%x\n"),
    545               unit, port, ability->speed_full_duplex, ability->pause));
    546     return SOC_E_NONE;
    547 }
    548 
    549 /*
    550 * Function:
    551 *      phy_8750_ability_remote_get
    552 * Purpose:
    553 *      Get the device's complete abilities.
    554 * Parameters:
    555 *      unit - StrataSwitch unit #.
    556 *      port - StrataSwitch port #.
    557 *      ability - return device's abilities.
    558 * Returns:
    559 *      SOC_E_XXX
    560 */
    561 
    562 STATIC int
    563 phy_8750_ability_remote_get(int unit, soc_port_t port, 
    564                             soc_port_ability_t *ability)
    565 {
    566     phy_ctrl_t *pc;
    567     uint16      lp_abil;
    568 
    569     pc = EXT_PHY_SW_STATE(unit, port);
    570                                            
    571     if (NULL == ability) {
    572         return SOC_E_PARAM;
    573     }
    574                                           
    575     SOC_IF_ERROR_RETURN
    576         (READ_PHY8750_MMF_AN_REG(unit, pc, 0xFFE5, &lp_abil));
    577     ability->speed_full_duplex  = (lp_abil & MII_ANA_C37_FD) ? 
    578                                    SOC_PA_SPEED_1000MB : 0;
    579 
    580     ability->pause = 0;
    581     switch (lp_abil & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
    582         case MII_ANP_C37_PAUSE:
    583             ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX;
    584             break;
    585         case MII_ANP_C37_ASYM_PAUSE:
    586             ability->pause = SOC_PA_PAUSE_TX;
    587             break;
    588         case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE:
    589             ability->pause = SOC_PA_PAUSE_RX;
    590             break;
    591     }
    592 
    593     SOC_IF_ERROR_RETURN
    594         (READ_PHY8750_MMF_AN_REG(unit, pc, PHY8750_AN_STATUS_REG, &lp_abil));
    595     ability->flags     = (lp_abil & 0x1) ? SOC_PA_AUTONEG : 0;
    596 
    597     LOG_INFO(BSL_LS_SOC_PHY,
    598              (BSL_META_U(unit,
    599                          "phy_8750_ability_remote_get: u=%d p=%d speed(FD)=0x%x pause=0x%x\n"),
    600               unit, port, ability->speed_full_duplex, ability->pause));
    601 
    602     return (SOC_E_NONE);
    603 }
    604 
    605 /*
    606  * Function:
    607  *      phy_8750_ability_advert_set
    608  * Purpose:
    609  *      Set the current advertisement for auto-negotiation.
    610  * Parameters:
    611  *      unit - StrataSwitch unit #.
    612  *      port - StrataSwitch port #.
    613  *      mode - Port mode mask indicating supported options/speeds.
    614  * Returns:
    615  *      SOC_E_XXX
    616  * Notes:
    617  *      The advertisement is set only for the ACTIVE medium.
    618  *      No synchronization performed at this level.
    619  */
    620 
    621 STATIC int
    622 phy_8750_ability_advert_set(int unit, soc_port_t port,
    623                        soc_port_ability_t *ability)
    624 {
    625     uint16           an_adv;
    626     phy_ctrl_t      *pc;
    627 
    628     if (NULL == ability) {
    629         return (SOC_E_PARAM);
    630     }
    631 
    632     pc = EXT_PHY_SW_STATE(unit, port);
    633     /*
    634      * Set advertised duplex (only FD supported).
    635      */
    636     an_adv =  (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? 
    637                MII_ANA_C37_FD : 0;
    638 
    639     switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) {
    640         case SOC_PA_PAUSE_TX:
    641             an_adv |= MII_ANA_C37_ASYM_PAUSE;
    642             break;
    643         case SOC_PA_PAUSE_RX:
    644             an_adv |= MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE;
    645             break;
    646         case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX:
    647             an_adv |= MII_ANA_C37_PAUSE;
    648             break;
    649     }
    650 
    651     /* write Clause37 advertisement */
    652     SOC_IF_ERROR_RETURN
    653         (MODIFY_PHY8750_MMF_AN_REG(unit, pc, 0xFFE4, an_adv, 
    654                               MII_ANA_C37_ASYM_PAUSE | 
    655                               MII_ANA_C37_PAUSE |
    656                               MII_ANA_C37_FD |
    657                               MII_ANA_C37_HD ));
    658 
    659     /*Set on the XFI side as well */
    660     PHY8750_XFI(unit, pc);
    661     /* write Clause37 advertisement */
    662     SOC_IF_ERROR_RETURN
    663         (MODIFY_PHY8750_XFI_AN_REG(unit, pc, 0xFFE4, an_adv, 
    664                               MII_ANA_C37_ASYM_PAUSE | 
    665                               MII_ANA_C37_PAUSE |
    666                               MII_ANA_C37_FD |
    667                               MII_ANA_C37_HD ));
    668     PHY8750_MMF(unit, pc);
    669 
    670     LOG_INFO(BSL_LS_SOC_PHY,
    671              (BSL_META_U(unit,
    672                          "phy_8750_ability_advert_set: u=%d p=%d pause=0x%08x adv_reg1=0x%04x\n"),
    673               unit, port, ability->pause, an_adv));
    674     return SOC_E_NONE;
    675 }
    676 
    677 /*
    678  * Function:
    679  *      phy_8750_ability_local_get
    680  * Purpose:
    681  *      Get the device's complete abilities.
    682  * Parameters:
    683  *      unit - StrataSwitch unit #.
    684  *      port - StrataSwitch port #.
    685  *      ability - return device's abilities.
    686  * Returns:
    687  *      SOC_E_XXX
    688  */
    689 
    690 STATIC int
    691 phy_8750_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability)
    692 {
    693     phy_ctrl_t *pc;
    694     pc = EXT_PHY_SW_STATE(unit, port);
    695 
    696     LOG_INFO(BSL_LS_SOC_PHY,
    697              (BSL_META_U(unit,
    698                          "phy_8750_ability_local_get: u=%d p=%d\n"),
    699               unit, port));
    700                                                                                
    701     if (NULL == ability) {
    702         return SOC_E_PARAM;
    703     }
    704 
    705     ability->speed_half_duplex  = SOC_PA_ABILITY_NONE;
    706     ability->speed_full_duplex  = SOC_PA_SPEED_1000MB;
    707                                                                                
    708     switch(pc->speed_max) {
    709         case 10000:
    710         default:
    711             ability->speed_full_duplex |= SOC_PA_SPEED_10GB;
    712             break;
    713     }
    714                                                                                
    715     ability->pause     = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 
    716     ability->interface = SOC_PA_INTF_XGMII;
    717     ability->medium    = SOC_PA_MEDIUM_FIBER;
    718     ability->loopback  = SOC_PA_LB_PHY;
    719                                                                                
    720     LOG_INFO(BSL_LS_SOC_PHY,
    721              (BSL_META_U(unit,
    722                          "phy_8750_ability_local_get: u=%d p=%d speed=0x%x\n"),
    723               unit, port, ability->speed_full_duplex));
    724                                                                                
    725     return (SOC_E_NONE);
    726 }
    727 
    728 /*
    729  * Function:
    730  *    phy_8750_link_get
    731  * Purpose:
    732  *    Get layer2 connection status.
    733  * Parameters:
    734  *    unit - StrataSwitch unit #.
    735  *    port - StrataSwitch port #. 
    736  *      link - address of memory to store link up/down state.
    737  * Returns:    
    738  *    SOC_E_NONE
    739  */
    740 
    741 STATIC int
    742 phy_8750_link_get(int unit, soc_port_t port, int *link)
    743 {
    744     uint16      pma_mii_stat, pcs_mii_stat, link_stat;
    745     phy_ctrl_t *pc;
    746     int cur_speed = 0;
    747     int an = 0,an_done = 0;
    748     uint16 speed_val; 
    749 
    750     if (link == NULL) {
    751         return SOC_E_NONE;
    752     }
    753 
    754     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
    755         *link = FALSE;
    756         return SOC_E_NONE;
    757     }
    758 
    759     pc = EXT_PHY_SW_STATE(unit, port);
    760 
    761     phy_8750_an_get(unit,port,&an,&an_done);
    762 
    763     /* return link false if in the middle of autoneg */
    764     if (an == TRUE && an_done == FALSE) {
    765         *link = FALSE;
    766         return SOC_E_NONE;
    767     }
    768 
    769     /* AN only supports 1G */
    770     if (!an) {
    771         SOC_IF_ERROR_RETURN
    772             (READ_PHY8750_MMF_PMA_PMD_REG(unit,pc, PHY8750_PMAD_CTRL2_REG, 
    773                                           &speed_val));
    774         if ((speed_val & PHY8750_PMAD_CTRL2r_PMA_TYPE_MASK) !=
    775                                        PHY8750_PMAD_CTRL2r_PMA_TYPE_1G_KX) {
    776             cur_speed = 10000;
    777         } else {
    778             cur_speed = 1000;
    779         }
    780     } else {
    781         cur_speed = 1000;
    782     }
    783 
    784     if (cur_speed == 10000) { /* check all 3 device's link status if 10G */
    785 
    786         /* Receive Link status */
    787         SOC_IF_ERROR_RETURN
    788             (READ_PHY8750_PCS_STATr(unit, pc, &pcs_mii_stat));
    789 
    790         SOC_IF_ERROR_RETURN
    791             (READ_PHY8750_PMA_PMD_STATr(unit, pc, &pma_mii_stat));
    792 
    793         /* MMF link status */
    794         link_stat = pma_mii_stat & pcs_mii_stat;
    795         *link = (link_stat & MII_STAT_LA) ? TRUE : FALSE;
    796 
    797     } else {
    798         SOC_IF_ERROR_RETURN
    799             (READ_PHY8750_MMF_AN_REG(unit, pc, 0xffe1,
    800                                      &link_stat));
    801         *link = (link_stat & MII_STAT_LA) ? TRUE : FALSE;
    802     } 
    803 
    804     LOG_VERBOSE(BSL_LS_SOC_PHY,
    805                 (BSL_META_U(unit,
    806                             "phy_8750_link_get: u=%d port%d: link:%s\n"),
    807                  unit, port, *link ? "Up": "Down"));
    808 
    809     return SOC_E_NONE;
    810 }
    811 
    812 /*
    813  * Function:
    814  *    phy_8750_enable_set
    815  * Purpose:
    816  *    Enable/Disable phy 
    817  * Parameters:
    818  *    unit - StrataSwitch unit #.
    819  *    port - StrataSwitch port #. 
    820  *      enable - on/off state to set
    821  * Returns:    
    822  *    SOC_E_NONE
    823  */
    824 
    825 STATIC int
    826 phy_8750_enable_set(int unit, soc_port_t port, int enable)
    827 {
    828     uint16      data;       /* Holder for new value to write to PHY reg */
    829     uint16      mask;       /* Holder for bit mask to update in PHY reg */
    830     phy_ctrl_t *pc;
    831 
    832     pc = EXT_PHY_SW_STATE(unit, port);
    833 
    834     data = 0;
    835     mask = 1 << 0; /* Global PMD transmit disable */
    836     if (enable) {
    837         PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE);
    838     } else {
    839         data = 1 << 0;  /* Global PMD transmit disable */
    840         PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE);
    841     }
    842 
    843     SOC_IF_ERROR_RETURN
    844         (MODIFY_PHY8750_PMA_PMD_TX_DISABLEr(unit, pc, data, mask));
    845 
    846     data = mask = 1 << 11; /* Disable clock for low power*/
    847     if (enable) {
    848         data = 0;
    849     }
    850     SOC_IF_ERROR_RETURN   
    851         (MODIFY_PHY8750_PMA_PMD_CTRLr(unit, pc, data, mask));
    852     
    853     return (SOC_E_NONE);
    854 }
    855 
    856 /*
    857  * Function:
    858  *    phy_8750_lb_set
    859  * Purpose:
    860  *    Put 8750 in PHY PMA/PMD loopback
    861  * Parameters:
    862  *    unit - StrataSwitch unit #.
    863  *    port - StrataSwitch port #. 
    864  *      enable - binary value for on/off (1/0)
    865  * Returns:    
    866  *    SOC_E_NONE
    867  */
    868 
    869 STATIC int
    870 phy_8750_lb_set(int unit, soc_port_t port, int enable)
    871 {
    872     phy_ctrl_t *pc; 
    873     uint16     tmp;
    874 
    875     pc = EXT_PHY_SW_STATE(unit, port);
    876 
    877     tmp = enable ? PHY8750_MII_CTRL_PMA_LOOPBACK : 0;
    878 
    879     SOC_IF_ERROR_RETURN
    880         (MODIFY_PHY8750_PMA_PMD_CTRLr(unit, pc,
    881                                       tmp, PHY8750_MII_CTRL_PMA_LOOPBACK));
    882     return SOC_E_NONE;
    883 }
    884 
    885 /*
    886  * Function:
    887  *    phy_8750_lb_get
    888  * Purpose:
    889  *    Get 8750 PHY loopback state
    890  * Parameters:
    891  *    unit - StrataSwitch unit #.
    892  *    port - StrataSwitch port #. 
    893  *      enable - address of location to store binary value for on/off (1/0)
    894  * Returns:    
    895  *    SOC_E_NONE
    896  */
    897 
    898 STATIC int
    899 phy_8750_lb_get(int unit, soc_port_t port, int *enable)
    900 {
    901     uint16      tmp;
    902     phy_ctrl_t *pc;
    903 
    904     pc = EXT_PHY_SW_STATE(unit, port);
    905 
    906     SOC_IF_ERROR_RETURN
    907         (READ_PHY8750_PMA_PMD_CTRLr(unit, pc, &tmp));
    908     *enable = (tmp & PHY8750_MII_CTRL_PMA_LOOPBACK) ? TRUE : FALSE;
    909 
    910     LOG_INFO(BSL_LS_SOC_PHY,
    911              (BSL_META_U(unit,
    912                          "phy_8750_lb_get: u=%d port%d: loopback:%s\n"),
    913               unit, port, *enable ? "Enabled": "Disabled"));
    914     
    915     return SOC_E_NONE;
    916 }
    917 
    918 STATIC int
    919 _phy_8750_control_tx_driver_set(int unit, soc_port_t port,
    920                                 soc_phy_control_t type, uint32 value)
    921 {
    922     uint16       data;  /* Temporary holder of reg value to be written */
    923     uint16       mask;  /* Bit mask of reg value to be updated */
    924     phy_ctrl_t  *pc;    /* PHY software state */
    925 
    926     pc = EXT_PHY_SW_STATE(unit, port);
    927 
    928     /* Dozen SerDes */
    929     switch(type) {
    930     case SOC_PHY_CONTROL_PREEMPHASIS:
    931          data = (uint16)(value & 0xf);
    932          data = data << 12;
    933          mask = 0xf000;
    934          break;
    935     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    936          data = (uint16)(value & 0xf);
    937          data = data << 8;
    938          mask = 0x0f00;
    939          break;
    940     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    941          data = (uint16)(value & 0xf);
    942          data = data << 4;
    943          mask = 0x00f0;
    944          break;
    945     default:
    946          /* should never get here */
    947          return SOC_E_PARAM;
    948     }
    949     SOC_IF_ERROR_RETURN
    950         (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xca05, data, mask));
    951 
    952     return SOC_E_NONE;
    953 }
    954 
    955 STATIC int
    956 _phy_8750_control_tx_driver_get(int unit, soc_port_t port,
    957                                 soc_phy_control_t type, uint32 *value)
    958 {
    959     uint16         data16;   /* Temporary holder of a reg value */
    960     phy_ctrl_t    *pc;       /* PHY software state */
    961 
    962     pc = EXT_PHY_SW_STATE(unit, port);
    963 
    964     data16 = 0;
    965     SOC_IF_ERROR_RETURN
    966         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xca05, &data16));
    967     switch(type) {
    968     case SOC_PHY_CONTROL_PREEMPHASIS:
    969          *value = (data16 & 0xf000) >> 12;
    970          break;
    971     case SOC_PHY_CONTROL_DRIVER_CURRENT:
    972          *value = (data16 & 0x0f00) >> 8;
    973          break;
    974     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
    975          *value = (data16 & 0x00f0) >> 4;
    976          break;
    977     default:
    978          /* should never get here */
    979          return SOC_E_PARAM;
    980     }
    981 
    982     return SOC_E_NONE;
    983 }
    984 
    985 /*
    986  * Function:
    987  *      phy_8750_control_set
    988  * Purpose:
    989  *      Configure PHY device specific control fucntion.
    990  * Parameters:
    991  *      unit  - StrataSwitch unit #.
    992  *      port  - StrataSwitch port #.
    993  *      type  - Control to update
    994  *      value - New setting for the control
    995  * Returns:
    996  *      SOC_E_NONE
    997  */
    998 STATIC int
    999 phy_8750_control_set(int unit, soc_port_t port,
   1000                      soc_phy_control_t type, uint32 value)
   1001 {
   1002     int rv;
   1003 
   1004     PHY_CONTROL_TYPE_CHECK(type);
   1005 
   1006     rv = SOC_E_UNAVAIL;
   1007     switch(type) {
   1008     case SOC_PHY_CONTROL_PREEMPHASIS:
   1009         /* fall through */
   1010     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1011         /* fall through */
   1012     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1013         rv = _phy_8750_control_tx_driver_set(unit, port, type, value);
   1014         break;
   1015     default:
   1016         rv = SOC_E_UNAVAIL;
   1017         break;
   1018     }
   1019     return rv;
   1020 }
   1021 /*
   1022  * Function:
   1023  *      phy_8750_control_get
   1024  * Purpose:
   1025  *      Get current control settign of the PHY.
   1026  * Parameters:
   1027  *      unit  - StrataSwitch unit #.
   1028  *      port  - StrataSwitch port #.
   1029  *      type  - Control to update
   1030  *      value - (OUT)Current setting for the control
   1031  * Returns:
   1032  *      SOC_E_NONE
   1033  */
   1034 STATIC int
   1035 phy_8750_control_get(int unit, soc_port_t port,
   1036                      soc_phy_control_t type, uint32 *value)
   1037 {
   1038     int rv;
   1039 
   1040     PHY_CONTROL_TYPE_CHECK(type);
   1041 
   1042     rv = SOC_E_UNAVAIL;
   1043     switch(type) {
   1044     case SOC_PHY_CONTROL_PREEMPHASIS:
   1045         /* fall through */
   1046     case SOC_PHY_CONTROL_DRIVER_CURRENT:
   1047         /* fall through */
   1048     case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT:
   1049         rv = _phy_8750_control_tx_driver_get(unit, port, type, value);
   1050         break;
   1051     default:
   1052         rv = SOC_E_UNAVAIL;
   1053         break;
   1054     }
   1055 
   1056     return rv;
   1057 }
   1058 
   1059 /*
   1060  * Function:
   1061  *      phy_8750_speed_set
   1062  * Purpose:
   1063  *      Set PHY speed
   1064  * Parameters:
   1065  *      unit - StrataSwitch unit #.
   1066  *      port - StrataSwitch port #.
   1067  *      speed - link speed in Mbps
   1068  * Returns:
   1069  *      SOC_E_NONE
   1070  */
   1071 
   1072 STATIC int
   1073 phy_8750_speed_set(int unit, soc_port_t port, int speed)
   1074 {
   1075     phy_ctrl_t  *pc;
   1076     phy_ctrl_t  *int_pc;
   1077     int rv = SOC_E_NONE;
   1078 
   1079 
   1080     LOG_INFO(BSL_LS_SOC_PHY,
   1081              (BSL_META_U(unit,
   1082                          "phy_8750_speed_set: u=%d p=%d speed=%d\n"), 
   1083                          unit, port,speed));
   1084 
   1085     if (!(speed == 10000 || speed == 1000)) {
   1086         return SOC_E_PARAM;
   1087     }
   1088 
   1089     pc = EXT_PHY_SW_STATE(unit, port);
   1090 
   1091     if (speed == 10000) {
   1092         SOC_IF_ERROR_RETURN
   1093             (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit,pc, PHY8750_PMAD_CTRL_REG,
   1094                                             MII_CTRL_SS_LSB,
   1095                                             MII_CTRL_SS_LSB));
   1096         SOC_IF_ERROR_RETURN
   1097             (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit,pc, PHY8750_PMAD_CTRL2_REG,
   1098                                         PHY8750_PMAD_CTRL2r_PMA_TYPE_10G_LRM, 
   1099                                         PHY8750_PMAD_CTRL2r_PMA_TYPE_MASK));
   1100 
   1101         SOC_IF_ERROR_RETURN
   1102             (WRITE_PHY8750_MMF_AN_REG(unit, pc, PHY8750_AN_CTRL_REG,
   1103                                       PHY8750_AN_ENABLE |
   1104                                       PHY8750_AN_RESTART));
   1105         sal_usleep(40000);
   1106         SOC_IF_ERROR_RETURN
   1107             (WRITE_PHY8750_MMF_AN_REG(unit,pc, PHY8750_AN_CTRL_REG, 0x0));
   1108 
   1109     } else {
   1110         SOC_IF_ERROR_RETURN
   1111             (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit,pc, PHY8750_PMAD_CTRL2_REG,
   1112                                         PHY8750_PMAD_CTRL2r_PMA_TYPE_1G_KX,
   1113                                         PHY8750_PMAD_CTRL2r_PMA_TYPE_MASK));
   1114         SOC_IF_ERROR_RETURN
   1115             (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit,pc, MII_CTRL_REG,
   1116                                         0, MII_CTRL_SS_LSB));
   1117 
   1118     }
   1119     /* need to set the internal phy's speed accordingly */
   1120 
   1121     int_pc = INT_PHY_SW_STATE(unit, port);
   1122     if (NULL != int_pc) {
   1123         rv = PHY_SPEED_SET(int_pc->pd, unit, port, speed);
   1124     }
   1125     return rv;
   1126 }
   1127 
   1128 /*
   1129  * Function:
   1130  *      phy_8750_speed_get
   1131  * Purpose:
   1132  *      Get PHY speed
   1133  * Parameters:
   1134  *      unit - StrataSwitch unit #.
   1135  *      port - StrataSwitch port #.
   1136  *      speed - current link speed in Mbps
   1137  * Returns:
   1138  *      SOC_E_NONE
   1139  */
   1140 
   1141 STATIC int
   1142 phy_8750_speed_get(int unit, soc_port_t port, int *speed)
   1143 {
   1144     phy_ctrl_t  *pc;
   1145     uint16       speed_val;
   1146     int an = 0;
   1147     int an_done = 0;
   1148 
   1149     pc = EXT_PHY_SW_STATE(unit, port);
   1150 
   1151     phy_8750_an_get(unit,port,&an,&an_done);
   1152 
   1153     *speed = 0;
   1154     if (an) { /* autoneg is enabled */
   1155         if (an_done) { 
   1156             *speed = 1000;  /* can only do 1G autoneg */
   1157         }
   1158     } else { /* autoneg is not enabled, forced speed */
   1159         SOC_IF_ERROR_RETURN
   1160             (READ_PHY8750_MMF_PMA_PMD_REG(unit,pc, PHY8750_PMAD_CTRL2_REG, &speed_val));
   1161         if ((speed_val & PHY8750_PMAD_CTRL2r_PMA_TYPE_MASK) ==
   1162                                                 PHY8750_PMAD_CTRL2r_PMA_TYPE_1G_KX) {
   1163             *speed = 1000;
   1164         } else {
   1165             *speed = 10000;
   1166         }
   1167     }    
   1168     return SOC_E_NONE;
   1169 }
   1170 
   1171 /*
   1172  * Function:
   1173  *      _phy8754_mdio_firmware_download
   1174  * Purpose:
   1175  *      write the given firmware to the internal RAM
   1176  * Parameters:
   1177  *      unit - StrataSwitch unit #.
   1178  *      port - StrataSwitch port #.
   1179  *      offset - offset to the data stream
   1180  *      array  - the given data
   1181  *      datalen- the data length
   1182  * Returns:
   1183  *      SOC_E_NONE
   1184  */
   1185 
   1186 STATIC int
   1187 _phy8754_mdio_firmware_download(int unit, int port, int offset, uint8 *array,int datalen)
   1188 {
   1189     int j;
   1190     phy_ctrl_t *pc;
   1191     uint16 data16;
   1192     uint16 mask16;
   1193 
   1194     if (array == NULL) {
   1195         return SOC_E_PARAM;
   1196     }
   1197 
   1198     pc = EXT_PHY_SW_STATE(unit, port);
   1199 
   1200     /* Programme SPA Control Register to Boot from MDIO 
   1201      * bit 15, 0 MDIO for serial boot. bit 14, 1 serial boot
   1202      */
   1203     mask16 = (1 << 14) | (1 << 15);
   1204     data16 = 1 << 14;
   1205     SOC_IF_ERROR_RETURN
   1206         (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, PHY8750_PMAD_SPA_CTRL_REG,
   1207                                         data16,mask16));
   1208 
   1209     /* Reset, to download code from MDIO */
   1210     SOC_IF_ERROR_RETURN
   1211         (READ_PHY8750_PMA_PMD_CTRLr(unit, pc, &data16));
   1212 
   1213     data16 |= 0x8000;
   1214 
   1215     SOC_IF_ERROR_RETURN
   1216         (WRITE_PHY8750_PMA_PMD_CTRLr(unit, pc, data16));
   1217 
   1218     sal_usleep(3000); /* Wait for 3ms */
   1219 
   1220     /* Write Starting Address, where the Code will reside in SRAM */
   1221     data16 = 0xC000;
   1222     SOC_IF_ERROR_RETURN
   1223         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
   1224                               PHY8750_PMAD_M8051_MSGIN_REG, data16));
   1225     sal_udelay(20); /* Wait for 15us */
   1226 
   1227     /* Write SPI SRAM Count Size */
   1228     data16 = (datalen)/2;
   1229     SOC_IF_ERROR_RETURN
   1230         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
   1231                               PHY8750_PMAD_M8051_MSGIN_REG, data16));
   1232     sal_udelay(20); /* Wait for 15us */
   1233 
   1234     /* Fill in the SPI RAM */
   1235     for (j = 0; j < datalen/2; j++) {
   1236         data16 = (array[2*j] << 8) | array[2*j+1];
   1237         SOC_IF_ERROR_RETURN
   1238             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
   1239                                PHY8750_PMAD_M8051_MSGIN_REG, data16));
   1240 
   1241         /* Make sure the word is read by the Micro */
   1242         sal_udelay(20); /* Wait for 15us */
   1243     }
   1244 
   1245     /* Read Hand-Shake message (Done) from Micro */
   1246     SOC_IF_ERROR_RETURN
   1247         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
   1248                                  PHY8750_PMAD_M8051_MSGOUT_REG, &data16));
   1249 
   1250     if (data16 != 0x4321) {
   1251         /* Download failure */
   1252         LOG_CLI((BSL_META_U(unit,
   1253                             "_phy8754_mdio_firmware_download fail,p=%d done msg 0x%x\n"),
   1254                  port,data16));
   1255         return SOC_E_FAIL;
   1256     }
   1257 
   1258     /* Clear LASI status */
   1259     SOC_IF_ERROR_RETURN
   1260         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
   1261                                  PHY8750_PMAD_RX_ALARM_STAT_REG, &data16));
   1262 
   1263     /* Wait for LASI to be asserted when M8051 writes checksum to MSG_OUTr */
   1264     sal_udelay(400); /* Wait for 300us */
   1265 
   1266     /* read message out reg */
   1267     SOC_IF_ERROR_RETURN
   1268         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
   1269                                  PHY8750_PMAD_M8051_MSGOUT_REG, &data16));
   1270 
   1271     LOG_INFO(BSL_LS_SOC_PHY,
   1272              (BSL_META_U(unit,
   1273                          "_phy8754_mdio_firmware_download: p=%d msgout 0x%x\n"), 
   1274                          port,data16));
   1275 
   1276     /* clear LASI  */
   1277     SOC_IF_ERROR_RETURN
   1278         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 
   1279                                  PHY8750_PMAD_RX_ALARM_STAT_REG, &data16));
   1280 
   1281     SOC_IF_ERROR_RETURN
   1282         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA1C, &data16));
   1283 
   1284     /* check if checksum is correct */
   1285     if (data16 != 0x600D) {
   1286         /* Bad CHECKSUM */
   1287         LOG_CLI((BSL_META_U(unit,
   1288                             "_phy8754_mdio_firmware_download, bad cksum: "
   1289                             "p=%d, cksum=0x%x\n"),
   1290                  port, data16));
   1291         return SOC_E_FAIL;
   1292     }
   1293 
   1294     return SOC_E_NONE;
   1295 }
   1296 
   1297 /*
   1298  *  Function:  *      phy_8750_rom_wait
   1299  *
   1300  *  Purpose:
   1301  *      Wait for data to be written to the SPI-ROM.
   1302  *  Input:
   1303  *      unit, port
   1304  */
   1305 STATIC int
   1306 phy_8750_rom_wait(int unit, int port)
   1307 {
   1308     uint16     rd_data;     
   1309     uint16     wr_data;
   1310     int        count;     
   1311     phy_ctrl_t *pc;
   1312     soc_timeout_t to;     
   1313     int        SPI_READY; 
   1314 
   1315     pc = EXT_PHY_SW_STATE(unit, port);
   1316 
   1317     rd_data = 0;
   1318     soc_timeout_init(&to, WR_TIMEOUT, 0);
   1319     do {
   1320         /* Write SPI Control Register Read Command. */
   1321         count = 1;
   1322         wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count);
   1323         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1324         wr_data = SPI_CTRL_1_L;
   1325         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1326         if (rd_data & 0x0100) {
   1327             break;
   1328         }
   1329     } while (!soc_timeout_check(&to));
   1330     if (!(rd_data & 0x0100)) {
   1331         LOG_ERROR(BSL_LS_SOC_PHY,
   1332                   (BSL_META_U(unit,
   1333                               "phy_8750_rom_program: u = %d p = %d "
   1334                               "timeout 1\n"), unit, port));
   1335         return SOC_E_TIMEOUT;
   1336     }
   1337 
   1338     SPI_READY = 1;
   1339     while (SPI_READY == 1) {
   1340         /* Set-up SPI Controller To Receive SPI EEPROM Status. */
   1341         count = 1;
   1342         wr_data = ((WR_CPU_CTRL_REGS * 0x0100) | count);
   1343         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1344         wr_data = SPI_CTRL_2_H;
   1345         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1346         wr_data = 0x0100;
   1347         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1348         /* Fill-up SPI Transmit Fifo To check SPI Status. */
   1349         count = 2;
   1350         wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1351         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1352         /* Write Tx Fifo Register Address. */
   1353         wr_data = SPI_TXFIFO;
   1354         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1355 
   1356         /* Write SPI Tx Fifo Control Word-1. */
   1357         wr_data = ((1 * 0x0100) | MSGTYPE_HRD);
   1358         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1359         /* Write SPI Tx Fifo Control Word-2. */
   1360         wr_data = RDSR_OPCODE;
   1361         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1362         /* Write SPI Control Register Write Command. */
   1363         count = 2;
   1364         wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1365         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1366         /* Write SPI Control -1 Register Address. */
   1367         wr_data = SPI_CTRL_1_L;
   1368         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1369         /* Write SPI Control -1 Register Word-1. */
   1370         wr_data = 0x0101;
   1371         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1372         /* Write SPI Control -1 Register Word-2. */
   1373         wr_data = 0x0100;
   1374         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1375         /* Write SPI Control Register Write Command. */
   1376         count = 1;
   1377         wr_data = ((WR_CPU_CTRL_REGS * 0x0100) | count);
   1378         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1379         /* Write SPI Control -1 Register Address. */
   1380         wr_data = SPI_CTRL_1_H;
   1381         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1382         /* Write SPI Control -1 Register Word-2. */
   1383         wr_data = 0x0103;
   1384         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1385         /* Wait For 64 bytes To be written.   */
   1386         rd_data = 0x0000;
   1387         soc_timeout_init(&to, WR_TIMEOUT, 0);
   1388         do {
   1389             count = 1;
   1390             wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count);
   1391             SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1392             wr_data = SPI_CTRL_1_L;
   1393             SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1394             if (rd_data & 0x0100) {
   1395                 break;
   1396             }
   1397         } while (!soc_timeout_check(&to));
   1398         if (!(rd_data & 0x0100)) {
   1399             LOG_ERROR(BSL_LS_SOC_PHY,
   1400                       (BSL_META_U(unit,
   1401                                   "phy_8750_rom_program: u = %d p = %d "
   1402                                   "timeout 2\n"), unit, port));
   1403             return SOC_E_TIMEOUT;
   1404         }
   1405         /* Write SPI Control Register Read Command. */
   1406         count = 1;
   1407         wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count);
   1408         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1409         /* Write SPI Control -1 Register Address. */
   1410         wr_data = SPI_RXFIFO;
   1411 
   1412         SOC_IF_ERROR_RETURN         
   1413             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA12, wr_data));
   1414         SOC_IF_ERROR_RETURN
   1415             (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA13, &rd_data));
   1416 
   1417         /* Clear LASI Message Out Status. */
   1418         SOC_IF_ERROR_RETURN
   1419             (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9003, &wr_data));
   1420 
   1421         if ((rd_data & 0x1) == 0) {
   1422             SPI_READY = 0;
   1423         }
   1424     } /* SPI_READY  */
   1425     return SOC_E_NONE;
   1426 }
   1427 
   1428 
   1429 /*
   1430  * Function:
   1431  *      phy_8750_rom_write_enable_set
   1432  *
   1433  * Purpose:
   1434  *      Enable disable protection on SPI_EEPROM
   1435  *
   1436  * Input:
   1437  *      unit
   1438  *      port
   1439  *      enable
   1440  * Output:
   1441  *      SOC_E_xxx
   1442  *
   1443  * Notes:
   1444  *          25AA256 256Kbit Serial EEPROM
   1445  *          STATUS Register
   1446  *          +------------------------------------------+
   1447  *          | WPEN | x | x | x | BP1 | BP0 | WEL | WIP |
   1448  *          +------------------------------------------+
   1449  *      BP1 BP0  :   Protected Blocks
   1450  *       0   0   :  Protect None
   1451  *       1   1   :  Protect All
   1452  *
   1453  *      WEL : Write Latch Enable
   1454  *       0  : Do not allow writes
   1455  *       1  : Allow writes
   1456  */
   1457 
   1458 STATIC int
   1459 phy_8750_rom_write_enable_set(int unit, int port, int enable)
   1460 {
   1461     uint16     rd_data;
   1462     uint16     wr_data;
   1463     uint8      wrsr_data;
   1464     int        count;
   1465     phy_ctrl_t *pc;
   1466 
   1467     pc = EXT_PHY_SW_STATE(unit, port);
   1468 
   1469     /*
   1470      * Write SPI Control Register Write Command.
   1471      */
   1472     count = 2;
   1473     wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1474     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1475 
   1476     /*
   1477      * Write SPI Control -2 Register Address.
   1478      */
   1479     wr_data = SPI_CTRL_2_L;
   1480     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1481 
   1482     /*
   1483      * Write SPI Control -2 Register Word-1.
   1484      */
   1485     wr_data = 0x8200;
   1486     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1487 
   1488     /*
   1489      * Write SPI Control -2 Register Word-2.
   1490      */
   1491     wr_data = 0x0100;
   1492     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1493 
   1494     /*
   1495      * Fill-up SPI Transmit Fifo With SPI EEPROM Messages.
   1496      * Write SPI Control Register Write Command.
   1497      */
   1498     count = 4;
   1499     wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1500     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1501 
   1502     /*
   1503      * Write Tx Fifo Register Address.
   1504      */
   1505     wr_data = SPI_TXFIFO;
   1506     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1507 
   1508     /*
   1509      * Write SPI Tx Fifo Control Word-1.
   1510      */
   1511     wr_data = ((1 * 0x0100) | MSGTYPE_HWR);
   1512     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1513 
   1514     /*
   1515      * Write SPI Tx Fifo Control Word-2.
   1516      */
   1517     wr_data = ((MSGTYPE_HWR * 0x0100) | WREN_OPCODE);
   1518     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1519 
   1520     /*
   1521      * Write SPI Tx Fifo Control Word-3.
   1522      */
   1523     wr_data = ((WRSR_OPCODE * 0x100) | (0x2));
   1524     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1525 
   1526     /*
   1527      * Write SPI Tx Fifo Control Word-4.
   1528      */
   1529     wrsr_data = enable ? 0x2 : 0xc;
   1530     wr_data = ((wrsr_data * 0x0100) | wrsr_data);
   1531     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1532 
   1533     /*
   1534      * Write SPI Control Register Write Command.
   1535      */
   1536     count = 2;
   1537     wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1538     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1539 
   1540     /*
   1541      * Write SPI Control -1 Register Address.
   1542      */
   1543     wr_data = SPI_CTRL_1_L;
   1544     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1545 
   1546     /*
   1547      * Write SPI Control -1 Register Word-1.
   1548      */
   1549     wr_data = 0x0101;
   1550     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1551 
   1552     /*
   1553      * Write SPI Control -1 Register Word-2.
   1554      */
   1555     wr_data = 0x0003;
   1556     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1557 
   1558     /*
   1559      * Wait For WRSR Command To be written.
   1560      */
   1561     SOC_IF_ERROR_RETURN(phy_8750_rom_wait(unit, port));
   1562 
   1563     return SOC_E_NONE;
   1564 }
   1565 
   1566 /*
   1567  * Function:
   1568  *      phy_8750_firmware_set
   1569  * Purpose:
   1570  *      program the given firmware into the SPI-ROM 
   1571  * Parameters:
   1572  *      unit - StrataSwitch unit #.
   1573  *      port - StrataSwitch port #.
   1574  *      offset - offset to the data stream
   1575  *      array  - the given data
   1576  *      datalen- the data length  
   1577  * Returns:
   1578  *      SOC_E_NONE
   1579  */
   1580 
   1581 STATIC int
   1582 phy_8750_firmware_set(int unit, int port, int offset, uint8 *array,int datalen)
   1583 {
   1584 
   1585     uint16     rd_data;
   1586     uint16     wr_data;
   1587     int        j;
   1588     int        i = 0;
   1589     int        count;
   1590     uint8      spi_values[WR_BLOCK_SIZE];
   1591     uint8      phy_id;
   1592     uint16     chip_id;
   1593     phy_ctrl_t *pc;
   1594 
   1595     pc = EXT_PHY_SW_STATE(unit, port);
   1596     phy_id = pc->phy_id;
   1597 
   1598     /* Read Chip IDs */
   1599     SOC_IF_ERROR_RETURN
   1600         (READ_PHY8750_PMA_PMD_CHIPIDr(unit, pc, &chip_id));
   1601     if (chip_id == 0x8754) {
   1602         /*
   1603          * Place all Micros in reset, GEN_CTRL
   1604          * CAVEAT:
   1605          *      To eliminate the interference with SPI Programming process
   1606          *      it is required to reset the MicroController in adjacent odd port.
   1607          *      i.e. if you are programming channel-0(2) of the 8754 then you need
   1608          *      to reset the microcontroller of channel-1(3).
   1609          *      The instruction below reset all channels in 8754.
   1610          */
   1611         phy_id = pc->phy_id;
   1612         for (i = 0; i < 4; i++) {
   1613             pc->phy_id = (phy_id & (~3)) + i; /* Port 3, 2, 1 and 0 */
   1614             SOC_IF_ERROR_RETURN
   1615                 (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA10, 0x018f));
   1616         }
   1617         pc->phy_id = phy_id;  /* restore original phy_id */
   1618 
   1619         /*
   1620          * Disable all port's SPI
   1621          * CAVEAT:
   1622          *      Always disable all ports associated with the 
   1623          *      SPI you are programming.
   1624          */
   1625         /*
   1626          * Write to register 0x1.C843 bits 3:0 to 4'b1111
   1627          */
   1628         phy_id = pc->phy_id;
   1629         for (i = 0; i < 4; i++) {
   1630             pc->phy_id = (phy_id & (~3)) + i; /* Port 3, 2, 1 and 0 */
   1631             SOC_IF_ERROR_RETURN
   1632                 (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC843, 0x000f));
   1633         }
   1634         pc->phy_id = phy_id;  /* restore original phy_id */
   1635 
   1636         /*
   1637          * Write to register 0x1.C840 bits 3:2 to 2'b11.
   1638          */
   1639         phy_id = pc->phy_id;
   1640         for (i = 0; i < 4; i++) {
   1641             pc->phy_id = (phy_id & (~3)) + i; /* Port 3, 2, 1 and 0 */
   1642             SOC_IF_ERROR_RETURN
   1643                 (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC840, 0x000c));
   1644         }
   1645         pc->phy_id = phy_id;
   1646 
   1647         /*
   1648          * Enable SPI for Port0
   1649          */    
   1650         SOC_IF_ERROR_RETURN
   1651             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC843, 0x0000));
   1652         SOC_IF_ERROR_RETURN
   1653             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC840, 0x0000));
   1654         /*
   1655          * Remove M8051 resets for port 0.
   1656          * and wait for Micro to complete Init.
   1657          */
   1658         SOC_IF_ERROR_RETURN
   1659             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA10, 0x0188));
   1660         sal_usleep(10000);
   1661 
   1662         /*
   1663          * Set bit 0 (spa enable) in C848 for master channel.
   1664          */ 
   1665         phy_id = pc->phy_id;
   1666         for (i = 0; i < 4; i++) {
   1667             pc->phy_id = (phy_id & (~3)) + i; /* Port 3, 2, 1 and 0 */
   1668             SOC_IF_ERROR_RETURN
   1669                 (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC848, 0x80f9));
   1670         }
   1671         pc->phy_id = phy_id;
   1672     }
   1673 
   1674     /* 
   1675      * Enable SPI ROM access in SPI control
   1676      */
   1677     if (chip_id == 0x8754) {
   1678         SOC_IF_ERROR_RETURN
   1679             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC848, 0xc0fd));
   1680     } else {
   1681         SOC_IF_ERROR_RETURN
   1682             (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC848, 0x80fd));
   1683     }
   1684 
   1685     /*
   1686      * ser_boot pin HIGH
   1687      */
   1688     SOC_IF_ERROR_RETURN
   1689         (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA85, 0x1, 0x1)); 
   1690     /*
   1691      * Read LASI Status registers To clear initial Failure status.
   1692      */
   1693     SOC_IF_ERROR_RETURN
   1694         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9003, &rd_data));
   1695     SOC_IF_ERROR_RETURN
   1696         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9004, &rd_data));
   1697     SOC_IF_ERROR_RETURN
   1698         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9005, &rd_data));
   1699 
   1700     /*
   1701      * Enable the LASI For Message out. 
   1702      */
   1703     SOC_IF_ERROR_RETURN
   1704         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9000, 0x0004));
   1705     /*
   1706      * 0x9002, bit 2 Is Rx Alarm enabled For LASI. 
   1707      */
   1708     SOC_IF_ERROR_RETURN
   1709         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9002, 0x0004));
   1710     /*
   1711      * Read Any Residual Message out register.
   1712      */
   1713     SOC_IF_ERROR_RETURN
   1714         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA13, &rd_data));
   1715     /*
   1716      * Clear LASI Message Out Status. 
   1717      */
   1718     SOC_IF_ERROR_RETURN
   1719         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9003, &rd_data));
   1720 
   1721     /* set SPI-ROM write enable */
   1722     SOC_IF_ERROR_RETURN(phy_8750_rom_write_enable_set(unit, port, 1));
   1723 
   1724     LOG_INFO(BSL_LS_SOC_PHY,
   1725              (BSL_META_U(unit,
   1726                          "init0: u=%d p=%d\n"),
   1727                          unit, port));
   1728 
   1729     for (j = 0; j < datalen; j += WR_BLOCK_SIZE) {
   1730         /*
   1731          * Setup SPI Controller. 
   1732          */
   1733         count = 2;
   1734         wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1735         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1736 
   1737         /* Write SPI Control -2 Register Address.*/
   1738         wr_data = SPI_CTRL_2_L;
   1739         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1740 
   1741         /* Write SPI Control -2 Register Word-1. */
   1742         wr_data = 0x8200;
   1743         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1744 
   1745         /* Write SPI Control -2 Register Word-2. */
   1746         wr_data = 0x0100;
   1747         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1748 
   1749         /* Fill-up SPI Transmit Fifo.
   1750          * Write SPI Control Register Write Command.
   1751          */
   1752         count = 4 + (WR_BLOCK_SIZE / 2);
   1753         wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1754         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1755 
   1756         /* Write Tx Fifo Register Address. */
   1757         wr_data = SPI_TXFIFO;
   1758         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1759 
   1760         /* Write SPI Tx Fifo Control Word-1. */
   1761         wr_data = ((1 * 0x0100) | MSGTYPE_HWR);
   1762         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1763 
   1764         /* Write SPI Tx Fifo Control Word-2. */
   1765         wr_data = ((MSGTYPE_HWR * 0x0100) | WREN_OPCODE);
   1766         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1767 
   1768         /* Write SPI Tx Fifo Control Word-3. */
   1769         wr_data = ((WR_OPCODE * 0x0100) | (0x3 + WR_BLOCK_SIZE));
   1770         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1771 
   1772         /* Write SPI Tx Fifo Control Word-4. */
   1773         wr_data = (((j & 0x00FF) * 0x0100) | ((j & 0xFF00) / 0x0100));
   1774         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1775 
   1776         LOG_INFO(BSL_LS_SOC_PHY,
   1777                  (BSL_META_U(unit,
   1778                              "loop: u=%d p=%d,inxj: %d,inxi:%d\n"),
   1779                              unit, port,j,i));
   1780 
   1781         if (datalen < (j + WR_BLOCK_SIZE)) {   /* last block */ 
   1782             sal_memset(spi_values,0,WR_BLOCK_SIZE);
   1783             sal_memcpy(spi_values,&array[j],datalen - j);
   1784 
   1785             for (i = 0; i < WR_BLOCK_SIZE; i += 2) {
   1786                 /* Write SPI Tx Fifo Data Word-4. */
   1787                 wr_data = ((spi_values[i+1] * 0x0100) | spi_values[i]);
   1788                 SOC_IF_ERROR_RETURN(write_message(unit, pc,wr_data, &rd_data));
   1789             }           
   1790         } else {        
   1791             for (i = 0; i < WR_BLOCK_SIZE; i += 2) {
   1792                 /* Write SPI Tx Fifo Data Word-4. */
   1793                 wr_data = ((array[j+i+1] * 0x0100) | array[j+i]);
   1794                 SOC_IF_ERROR_RETURN(write_message(unit, pc,wr_data, &rd_data));
   1795             }
   1796         }
   1797 
   1798         /* 
   1799          * Set-up SPI Controller To Transmit.
   1800          * Write SPI Control Register Write Command.
   1801          */
   1802         count = 2;
   1803         wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1804         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1805 
   1806         wr_data = SPI_CTRL_1_L;
   1807         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1808 
   1809         /* Write SPI Control -1 Register Word-1. */
   1810         wr_data = 0x0501;
   1811         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1812 
   1813         /* Write SPI Control -1 Register Word-2. */
   1814         wr_data = 0x0003;
   1815         SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1816 
   1817         /* Wait For 64 bytes To be written.   */
   1818         SOC_IF_ERROR_RETURN(phy_8750_rom_wait(unit,port));
   1819 
   1820     } /* SPI_WRITE */
   1821 
   1822     /* clear SPI-ROM write enable */
   1823     SOC_IF_ERROR_RETURN(phy_8750_rom_write_enable_set(unit, port, 0));
   1824 
   1825     /* Disable SPI EEPROM. */
   1826     count = 2;
   1827     wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1828     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1829 
   1830     /* Write SPI Control -2 Register Address. */
   1831     wr_data = SPI_CTRL_2_L;
   1832     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1833 
   1834     /* Write SPI Control -2 Register Word-1. */
   1835     wr_data = 0x8200;
   1836     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1837 
   1838     /* Write SPI Control -2 Register Word-2. */
   1839     wr_data = 0x0100;
   1840     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1841 
   1842 
   1843     /* Fill-up SPI Transmit Fifo With SPI EEPROM Messages. */
   1844     count = 2;
   1845     wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1846     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1847 
   1848     /* Write Tx Fifo Register Address. */
   1849     wr_data = SPI_TXFIFO;
   1850     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1851 
   1852     /* Write SPI Tx Fifo Control Word-1. */
   1853     wr_data = ((0x1*0x0100) | MSGTYPE_HWR);
   1854     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1855 
   1856     /* Write SPI Tx Fifo Control Word-2. */
   1857     wr_data = WRDI_OPCODE;
   1858     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1859 
   1860     /* Write SPI Control Register Write Command. */
   1861     count = 2;
   1862     wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count);
   1863     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1864 
   1865     /* Write SPI Control -1 Register Address. */
   1866     wr_data = SPI_CTRL_1_L;
   1867     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1868 
   1869     /* Write SPI Control -1 Register Word-1. */
   1870     wr_data = 0x0101;
   1871     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1872 
   1873     /* Write SPI Control -1 Register Word-2. */
   1874     wr_data = 0x0003;
   1875     SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data));
   1876 
   1877     /*
   1878      * ser_boot pin LOW
   1879      */
   1880     SOC_IF_ERROR_RETURN
   1881         (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA85, 0x0, 0x1)); 
   1882     /* 
   1883      * Disable SPI ROM access in SPI control
   1884      */
   1885     SOC_IF_ERROR_RETURN
   1886         (MODIFY_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xC848, 0xc0fd, 0xffff)); 
   1887 
   1888     LOG_INFO(BSL_LS_SOC_PHY,
   1889              (BSL_META_U(unit,
   1890                          "phy_8750_rom_program: u=%d p=%d done\n"), unit, port));
   1891 
   1892     return SOC_E_NONE;
   1893 }
   1894 
   1895 static int
   1896 write_message(int unit, phy_ctrl_t *pc, uint16 wrdata, uint16 *rddata)
   1897 {
   1898 
   1899     uint16     tmp_data = 0;
   1900     soc_timeout_t to;
   1901 
   1902     SOC_IF_ERROR_RETURN
   1903         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA13, &tmp_data));
   1904     SOC_IF_ERROR_RETURN
   1905         (WRITE_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA12, wrdata));
   1906 
   1907     soc_timeout_init(&to, WR_TIMEOUT, 0);
   1908     do {
   1909         SOC_IF_ERROR_RETURN
   1910             (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9005, &tmp_data));
   1911         if (tmp_data & 0x4)
   1912             break;
   1913     } while (!soc_timeout_check(&to));
   1914     if (!(tmp_data & 0x4)) {
   1915         LOG_ERROR(BSL_LS_SOC_PHY,
   1916                   (BSL_META_U(unit,
   1917                               "write_message failed: wrdata %04x\n"), wrdata));
   1918         return SOC_E_FAIL;
   1919     }
   1920 
   1921     SOC_IF_ERROR_RETURN
   1922         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0xCA13, &tmp_data));
   1923     *rddata = tmp_data;
   1924     SOC_IF_ERROR_RETURN
   1925         (READ_PHY8750_MMF_PMA_PMD_REG(unit, pc, 0x9003, &tmp_data));
   1926 
   1927     return SOC_E_NONE;
   1928 }
   1929 /*
   1930  * Function:
   1931  *      phy_8750_probe
   1932  * Purpose:
   1933  *      Complement the generic phy probe routine to identify this phy when its
   1934  *      phy id0 and id1 is same as some other phy's.
   1935  * Parameters:
   1936  *      unit - StrataSwitch unit #.
   1937  *      pc   - phy ctrl descriptor.
   1938  * Returns:
   1939  *      SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error>
   1940  */
   1941 STATIC int
   1942 phy_8750_probe(int unit, phy_ctrl_t *pc)
   1943 {
   1944     pc->size = sizeof(PHY8750_DEV_DESC_t);
   1945     return SOC_E_NONE;
   1946 }
   1947 
   1948 
   1949 /*
   1950  * Variable:
   1951  *    phy_8750_drv
   1952  * Purpose:
   1953  *    Phy Driver for 10G XFI to SFI PHY.
   1954  */
   1955 
   1956 phy_driver_t phy_8750drv_xe = {
   1957     "8750 10-Gigabit PHY Driver",
   1958     phy_8750_init,        /* Init */
   1959     phy_null_reset,       /* Reset (dummy) */
   1960     phy_8750_link_get,    /* Link get   */
   1961     phy_8750_enable_set,  /* Enable set */
   1962     phy_null_enable_get,  /* Enable get */
   1963     phy_null_set,         /* Duplex set */
   1964     phy_null_one_get,     /* Duplex get */
   1965     phy_8750_speed_set,   /* Speed set  */
   1966     phy_8750_speed_get,   /* Speed get  */
   1967     phy_null_set,         /* Master set */
   1968     phy_null_zero_get,    /* Master get */
   1969     phy_8750_an_set,      /* ANA set */
   1970     phy_8750_an_get,      /* ANA get */
   1971     NULL,                 /* Local Advert set */
   1972     NULL,                 /* Local Advert get */
   1973     phy_null_mode_get,    /* Remote Advert get */
   1974     phy_8750_lb_set,      /* PHY loopback set */
   1975     phy_8750_lb_get,      /* PHY loopback set */
   1976     phy_null_interface_set, /* IO Interface set */
   1977     phy_xehg_interface_get, /* IO Interface get */
   1978     NULL,   /* PHY abilities mask */
   1979     NULL,
   1980     NULL,
   1981     phy_null_mdix_set,
   1982     phy_null_mdix_get,
   1983     phy_null_mdix_status_get,
   1984     NULL,
   1985     NULL,
   1986     phy_null_medium_get,
   1987     NULL,                    /* phy_cable_diag  */
   1988     NULL,                    /* phy_link_change */
   1989     phy_8750_control_set,    /* phy_control_set */
   1990     phy_8750_control_get,    /* phy_control_get */
   1991     NULL,                    /* phy_reg_read */
   1992     NULL,                    /* phy_reg_write */
   1993     NULL,                    /* phy_reg_modify */
   1994     NULL,                    /* phy_notify */
   1995     phy_8750_probe,         /* pd_probe  */
   1996     phy_8750_ability_advert_set,  /* pd_ability_advert_set */
   1997     phy_8750_ability_advert_get,  /* pd_ability_advert_get */
   1998     phy_8750_ability_remote_get,  /* pd_ability_remote_get */
   1999     phy_8750_ability_local_get,   /* pd_ability_local_get  */
   2000     phy_8750_firmware_set         /* pd_firmware_set */
   2001 };
   2002 
   2003 #else /* INCLUDE_PHY_8750 */
   2004 int _phy_8750_not_empty;
   2005 #endif /* INCLUDE_PHY_8750 */
   2006