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