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

phy84756_i2c.c (7968B)


      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:        phy84756.c
      9  * Purpose:     SDK PHY driver for BCM84756 (FCMAP)
     10  *
     11  * Supported BCM546X Family of PHY devices:
     12  *
     13  *      Device  Ports    Media                           MAC Interface
     14  *      84756    4       4 10G SFP+                      XFI
     15  *      84757    4       4 10G SFP+/8(4/2) FC            XFI
     16  *      84759    4       4 10G SFP+                      XFI
     17  *
     18  *	             OUI	    Model	Revision
     19  *  BCM84756	18-C0-86	100111	00xx
     20  *  BCM84757	18-C0-86	100111	10xx
     21  *  BCM84759	18-C0-86	100111	01xx
     22  *
     23  *
     24  * Workarounds:
     25  *
     26  * References:
     27  *     
     28  * Notes:
     29  */ 
     30 
     31 
     32 #include <sal/types.h>
     33 #include <sal/core/spl.h>
     34 #include <shared/bsl.h>
     35 #include <soc/drv.h>
     36 #include <soc/debug.h>
     37 #include <soc/error.h>
     38 #include <soc/phyreg.h>
     39 
     40 #include <soc/phy.h>
     41 #include <soc/phy/phyctrl.h>
     42 #include <soc/phy/drv.h>
     43 
     44 #include "phydefs.h"      /* Must include before other phy related includes */
     45 
     46 
     47 
     48 #if defined(INCLUDE_FCMAP) || defined(INCLUDE_MACSEC)
     49 #if defined(INCLUDE_PHY_84756)
     50 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     51 #include "phyident.h"
     52 #include "phyreg.h"
     53 #include "phynull.h"
     54 #include "phyfege.h"
     55 #include "phyxehg.h"
     56 
     57 #if defined(INCLUDE_FCMAP)
     58 #include <soc/fcmapphy.h>
     59 #endif
     60 #if defined(INCLUDE_MACSEC)
     61 #include <soc/macsecphy.h>
     62 #endif
     63 #include "phy_mac_ctrl.h"
     64 #include "phy_xmac.h"
     65 #include "phy84756_fcmap_int.h"
     66 #include "phy84756_fcmap.h"
     67 #include "phy84756_i2c.h"
     68 
     69 int
     70 _phy_84756_bsc_rw(phy_ctrl_t *pc, int dev_addr, int opr,
     71                     int addr, int count, void *data_array,buint32_t ram_start)
     72 {
     73     int iter = 0;
     74     buint16_t data16;
     75     int i;
     76     int access_type;
     77     int data_type;
     78     if (!data_array) {
     79         return SOC_E_PARAM;
     80     }
     81 
     82     if (count > PHY84756_BSC_XFER_MAX) {
     83         return SOC_E_PARAM;
     84     }
     85 
     86     data_type = PHY84756_I2C_DATA_TYPE(opr);
     87     access_type = PHY84756_I2C_ACCESS_TYPE(opr);
     88 
     89     if (access_type == PHY84756_I2CDEV_WRITE) {
     90         for (i = 0; i < count; i++) {
     91             if (data_type == PHY84756_I2C_8BIT) {
     92                 SOC_IF_ERROR_RETURN
     93                     (BFCMAP_WR_PHY84756_LN_DEV1_PMDr(pc, ram_start + i,
     94                           ((buint8_t *)data_array)[i]));
     95             } else {  /* 16 bit */
     96                 SOC_IF_ERROR_RETURN
     97                     (BFCMAP_WR_PHY84756_LN_DEV1_PMDr(pc, ram_start + i,
     98                           ((buint16_t *)data_array)[i]));
     99             }
    100         }
    101     }
    102 
    103     data16 = ram_start;
    104     SOC_IF_ERROR_RETURN
    105         (BFCMAP_WR_PHY84756_LN_DEV1_PMDr(pc, 0x8004, data16));
    106     SOC_IF_ERROR_RETURN
    107         (BFCMAP_WR_PHY84756_LN_DEV1_PMDr(pc, 0x8003, addr));
    108     SOC_IF_ERROR_RETURN
    109         (BFCMAP_WR_PHY84756_LN_DEV1_PMDr(pc, 0x8002, count));
    110 
    111     data16 = 1;
    112     data16 |= (dev_addr<<9);
    113     if (access_type == PHY84756_I2CDEV_WRITE) {
    114         data16 |= PHY84756_WR_FREQ_400KHZ;
    115     }
    116 
    117     SOC_IF_ERROR_RETURN
    118         (BFCMAP_WR_PHY84756_LN_DEV1_PMDr(pc, 0x8005,data16));
    119 
    120     if (access_type == PHY84756_I2CDEV_WRITE) {
    121         data16 =  0x8000 | PHY84756_BSC_WRITE_OP;
    122     } else {
    123         data16 =  0x8000 | PHY84756_BSC_READ_OP;
    124     }
    125 
    126     if (data_type == PHY84756_I2C_16BIT) {
    127         data16 |= (1 << 12);
    128     }
    129 
    130     /* for single port mode, there should be only one I2C interface active
    131      * from lane0. The 0x800x register block is bcst type registers. If writing
    132      * to 0x8000 directly, it will enable all four I2C masters. Use indirect access
    133      * to enable only the lane 0.
    134      */
    135 
    136     SOC_IF_ERROR_RETURN
    137         (BFCMAP_WR_PHY84756_LN_DEV1_PMDr(pc, 0x8000, data16));
    138 
    139     while (iter < 100000) {
    140         SOC_IF_ERROR_RETURN
    141             (BFCMAP_RD_PHY84756_LN_DEV1_PMDr(pc, 0x8000, &data16));
    142         if (((data16 & PHY84756_2W_STAT) == PHY84756_2W_STAT_COMPLETE)) {
    143             break;
    144         }
    145         iter++;
    146     }
    147 
    148     /* need some delays */
    149     sal_usleep(10000);
    150 
    151     LOG_INFO(BSL_LS_SOC_PHY,
    152              (BSL_META_U(pc->unit,
    153                          "BSC command status %d\n"),(data16 & PHY84756_2W_STAT)));
    154 
    155     if (access_type == PHY84756_I2CDEV_WRITE) {
    156         return SOC_E_NONE;
    157     }
    158 
    159     if ((data16 & PHY84756_2W_STAT) == PHY84756_2W_STAT_COMPLETE) {
    160         for (i = 0; i < count; i++) {
    161             SOC_IF_ERROR_RETURN
    162                 (BFCMAP_RD_PHY84756_LN_DEV1_PMDr(pc, (ram_start+i), &data16));
    163             if (data_type == PHY84756_I2C_16BIT) {
    164                 ((buint16_t *)data_array)[i] = data16;
    165                 LOG_INFO(BSL_LS_SOC_PHY,
    166                          (BSL_META_U(pc->unit,
    167                                      "%04x "), data16));
    168             } else {
    169                 ((buint8_t *)data_array)[i] = (buint8_t)data16;
    170                 LOG_INFO(BSL_LS_SOC_PHY,
    171                          (BSL_META_U(pc->unit,
    172                                      "%02x "), data16));
    173             }
    174         }
    175     }
    176     return SOC_E_NONE;
    177 }
    178 
    179 /*
    180  * Read a slave device such as NVRAM/EEPROM connected to the 84740's I2C
    181  * interface. This function will be mainly used for diagnostic or workaround
    182  * purpose.
    183  * Note:
    184  * The size of read_array buffer must be greater than or equal to the
    185  * parameter nbytes.
    186  * usage example:
    187  *   Retrieve the first 100 byte data of the non-volatile storage device with
    188  *   I2C bus device address 0x50(default SPF eeprom I2C address) on unit 0,
    189  *   port 2.
    190  *   buint8_t data8[100];
    191  *   phy_84740_i2cdev_read(0,2,0x50,0,100,data8);
    192  */
    193 int
    194 phy_84756_i2cdev_read(phy_ctrl_t *pc,
    195                      int dev_addr,  /* 7 bit I2C bus device address */
    196                      int offset,    /* starting data address to read */
    197                      int nbytes,    /* number of bytes to read */
    198                      buint8_t *read_array)   /* buffer to hold retrieved data */
    199 {
    200     return _phy_84756_bsc_rw(pc, dev_addr,PHY84756_I2CDEV_READ,
    201              offset, nbytes, (void *)read_array,PHY84756_READ_START_ADDR);
    202 
    203 }
    204 
    205 /*
    206  * Write to a slave device such as NVRAM/EEPROM connected to the 84740's I2C
    207  * interface. This function will be mainly used for diagnostic or workaround
    208  * purpose.
    209  * Note:
    210  * The size of write_array buffer should be equal to the parameter nbytes.
    211  * The EEPROM may limit the maximun write size to 16 bytes
    212  * usage example:
    213  *   Write to first 100 byte space of the non-volatile storage device with
    214  *   I2C bus device address 0x50(default SPF eeprom I2C address) on unit 0,
    215  *   port 2, with written data specified in array data8.
    216  *   buint8_t data8[100];
    217  *   *** initialize the data8 array with written data ***
    218  *
    219  *   phy_84740_i2cdev_write(0,2,0x50,0,100,data8);
    220  */
    221 
    222 int
    223 phy_84756_i2cdev_write(phy_ctrl_t *pc,
    224                      int dev_addr,  /* I2C bus device address */
    225                      int offset,    /* starting data address to write to */
    226                      int nbytes,    /* number of bytes to write */
    227                      buint8_t *write_array)   /* buffer to hold written data */
    228 {
    229     int j;
    230     int rv = SOC_E_NONE;
    231 
    232     for (j = 0; j < (nbytes/PHY84756_BSC_WR_MAX); j++) {
    233         rv = _phy_84756_bsc_rw(pc, dev_addr,PHY84756_I2CDEV_WRITE,
    234                     offset + j * PHY84756_BSC_WR_MAX, PHY84756_BSC_WR_MAX,
    235                     (void *)(write_array + j * PHY84756_BSC_WR_MAX),
    236                     PHY84756_WRITE_START_ADDR);
    237         if (rv != SOC_E_NONE) {
    238             return rv;
    239         }
    240         sal_usleep(20000);
    241     }
    242     if (nbytes%PHY84756_BSC_WR_MAX) {
    243         rv = _phy_84756_bsc_rw(pc, dev_addr,PHY84756_I2CDEV_WRITE,
    244                 offset + j * PHY84756_BSC_WR_MAX, nbytes%PHY84756_BSC_WR_MAX,
    245                 (void *)(write_array + j * PHY84756_BSC_WR_MAX),
    246                 PHY84756_WRITE_START_ADDR);
    247     }
    248     return rv;
    249 }
    250 #else /* INCLUDE_PHY_84756 */
    251 int _phy_84756_fcmap_not_empty;
    252 #endif /* INCLUDE_PHY_84756 */
    253 #endif /* INCLUDE_FCMAP */
    254