phy84328.c (303527B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: phy84328.c 8 * Purpose: Phys Driver support for Broadcom 84328 40G phy 9 * Note: 10 * 11 * Specifications: 12 13 * Repeater mode only, no retimer operation. 14 15 * Supports the following data speeds: 16 * 1.25 Gbps line rate (1 GbE data rate, 8x oversampled over 10 Gbps line rate) 17 * 10.3125 Gbps line rate (10 GbE data rate) 18 * 11.5 Gpbs line rate (for backplane application, proprietary data rate) 19 * 4x10.3125 Gbps line rate (40 GbE data rate) 20 * 21 * Supports the following line-side connections: 22 * 1 GbE and 10 GbE SFP+ SR and LR optical modules 23 * 40 GbE QSFP SR4 and LR4 optical modules 24 * 1 GbE and 10 GbE SFP+ CR (CX1) copper cable 25 * 40 GbE QSFP CR4 copper cable 26 * 10 GbE KR, 11.5 Gbps line rate and 40 GbE KR4 backplanes 27 * 28 * Operates with the following reference clocks: 29 * Single 156.25 MHz differential clock for 1.25 Gbps, 10.3125 Gpbs and 11.5 Gbps 30 * line rates 31 * Single 125.00 MHz differential clock for 1.25 Gbps, 10.3125 Gbps and 11.5 Gbps 32 * line rates 33 * 34 * Supports autonegotiation as follows: 35 * Clause 73 only for starting Clause 72 and requesting FEC 36 * No speed resolution performed 37 * No Clause 73 in 11.5 Gbps line rate, only Clause 72 supported 38 * Clause 72 may be enabled standalone for close systems 39 * Clause 37 is not supported 40 * No on-chip FEC encoding/decoding, but shall pass-through FEC-encoded data. 41 */ 42 43 #if defined(INCLUDE_PHY_84328) 44 45 static unsigned int phy84328_maj_rev = 1200; 46 static unsigned int phy84328_min_rev = 0; 47 48 #include <sal/types.h> 49 #include <soc/drv.h> 50 #include <soc/debug.h> 51 #include <soc/error.h> 52 #include <soc/phyreg.h> 53 #include <shared/bsl.h> 54 #include <soc/phy.h> 55 #include <soc/phy/phyctrl.h> 56 #include <soc/phy/drv.h> 57 58 #include "phydefs.h" /* Must include before other phy related includes */ 59 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 60 #include "phyident.h" 61 #include "phyreg.h" 62 #include "phynull.h" 63 #include "phyxehg.h" 64 #include "phy84328.h" 65 66 #define PHY84328_SINGLE_PORT_MODE(_pc) \ 67 (SOC_INFO((_pc)->unit).port_num_lanes[(_pc)->port] >= 4) 68 #define PHY84328_ID_84328 0x84328 /* Gallardo_oct_opt */ 69 #define PHY84328_ID_84324 0x84324 /* Gallardo_opt */ 70 #define PHY84328_ID_84088 0x84088 /* Gallardo_oct_bp */ 71 #define PHY84328_ID_84024 0x84024 /* Gallardo_bp */ 72 /* PMD_CONTROL_REG - speed selection */ 73 #define PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_MASK \ 74 (PHY84328_DEV1_PMD_CONTROL_REGISTER_SPEED_SELECTIONLSB_MASK | \ 75 PHY84328_DEV1_PMD_CONTROL_REGISTER_SPEED_SELECTIONMSB_MASK | \ 76 PHY84328_DEV1_PMD_CONTROL_REGISTER_SPEED_SELECTION_MASK) 77 78 #define PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_SELECTIONLSB \ 79 (1 << PHY84328_DEV1_PMD_CONTROL_REGISTER_SPEED_SELECTIONLSB_SHIFT) 80 #define PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_SELECTIONMSB \ 81 (1 << PHY84328_DEV1_PMD_CONTROL_REGISTER_SPEED_SELECTIONMSB_SHIFT) 82 83 #define PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_10GB \ 84 (PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_SELECTIONLSB | \ 85 PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_SELECTIONMSB) 86 87 #define PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_40GB \ 88 (PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_SELECTIONLSB | \ 89 PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_SELECTIONMSB | \ 90 (2 << PHY84328_DEV1_PMD_CONTROL_REGISTER_SPEED_SELECTION_SHIFT)) 91 92 #define PHY84328_PMD_CONTROL_REG_VAL_4_SPEED_1GB \ 93 (1 << PHY84328_DEV1_PMD_CONTROL_REGISTER_SPEED_SELECTIONMSB_SHIFT) 94 95 #define PHY84328_DEV1_PMD_CONTROL_REGISTER_PMA_LOOPBACK \ 96 (1 << PHY84328_DEV1_PMD_CONTROL_REGISTER_PMA_LOOPBACK_SHIFT) 97 98 /* PMD_CONTROL_2_REG - PMA type selection */ 99 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_LR4 0x23 100 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_SR4 0x22 101 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_CR4 0x21 102 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_KR4 0x20 103 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_10BASET 0x0f 104 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_100BASETX 0x0e 105 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_KX 0x0d 106 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_1000BASET 0x0c 107 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_KR 0x0b 108 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_KX4 0x0a 109 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_10GBASET 0x09 110 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_LRM 0x08 111 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_SR 0x07 112 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_LR 0x06 113 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_ER 0x05 114 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_LX4 0x04 115 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_SW 0x03 116 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_LW 0x02 117 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_EW 0x01 118 #define PHY84328_DEV1_PMD_CONTROL_2_REGISTER_PMA_TYPE_CX4 0x00 119 120 /* GP_REGISTER_0 new defined bits */ 121 #define PHY84328_DEV1_GP_REG_0_P4_5_CTRL (1 << 1) 122 #define PHY84328_DEV1_GP_REG_0_TX_GPIO (1 << 2) 123 124 /* GP_REGISTER_1 */ 125 #define PHY84328_DEV1_GP_REGISTER_1_LINE_TYPE_BKPLANE (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_TYPE_SHIFT) 126 #define PHY84328_DEV1_GP_REGISTER_1_SYSTEM_TYPE_BKPLANE (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_TYPE_SHIFT) 127 #define PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_COPPER (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_SHIFT) 128 #define PHY84328_DEV1_GP_REGISTER_1_SYSTEM_CU_TYPE_COPPER (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_CU_TYPE_SHIFT) 129 #define PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE (1 << PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_SHIFT) 130 #define PHY84328_DEV1_GP_REGISTER_1_SPEED_100G (1 << PHY84328_DEV1_GP_REGISTER_1_SPEED_100G_SHIFT) 131 #define PHY84328_DEV1_GP_REGISTER_1_SPEED_42G ((1 << PHY84328_DEV1_GP_REGISTER_1_SPEED_40G_SHIFT) | \ 132 (1 << PHY84328_DEV1_GP_REGISTER_1_SPEED_1G_SHIFT) | \ 133 (1 << PHY84328_DEV1_GP_REGISTER_1_SPEED_10G_SHIFT)) 134 #define PHY84328_DEV1_GP_REGISTER_1_SPEED_40G (1 << PHY84328_DEV1_GP_REGISTER_1_SPEED_40G_SHIFT) 135 #define PHY84328_DEV1_GP_REGISTER_1_SPEED_10G (1 << PHY84328_DEV1_GP_REGISTER_1_SPEED_10G_SHIFT) 136 #define PHY84328_DEV1_GP_REGISTER_1_SPEED_1G (1 << PHY84328_DEV1_GP_REGISTER_1_SPEED_1G_SHIFT) 137 138 /* Datapath4 */ 139 #define PHY84328_DEV1_GP_REGISTER_1_DATAPATH_MASK 0x0060 140 #define PHY84328_DEV1_GP_REGISTER_1_DATAPATH_4_DEPTH1 0x0040 141 #define PHY84328_DEV1_GP_REGISTER_1_DATAPATH_4_DEPTH2 0x0060 142 143 /* GP_REGISTER_3 - microcode updated */ 144 #define PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK 0x0080 145 146 /* Rx polarity inversion */ 147 #define PHY84328_DEV1_GP_REGISTER_RX_INV 0xc0ba 148 #define PHY84328_DEV1_GP_REGISTER_RX_INV_FORCE (1 << 3) 149 #define PHY84328_DEV1_GP_REGISTER_RX_INV_INVERT (1 << 2) 150 151 /* ANARXSTATUS - link status */ 152 #define PHY84328_DEV1_ANARXSTATUS_RXSTATUS_SIGDET (1 << 15) 153 #define PHY84328_DEV1_ANARXSTATUS_RXSTATUS_CDR (1 << 12) 154 /* Available when PRBS status is selected in anaRxControl */ 155 #define PHY84328_DEV1_ANARXSTATUS_RXSTATUS_RX_PRBS_LOCK (1 << 15) 156 #define PHY84328_DEV1_ANARXSTATUS_RXSTATUS_RX_PRBS_ERR_MASK (0x1fff) 157 158 /* Squelching done with lectrical idles */ 159 #define PHY84328_DEV1_ANATXACONTROL2_TX_ELECTRAL_IDLE 0x0100 160 161 #define PHY84328_CSR_REG_MODULE_AUTO_DETECT (1 << 4) 162 /* 163 * This bounds how long to wait until giving up on configuration updates 164 * - Delay is given in us 165 * - timeout = (MAX_RETRIES * DELAY)us 166 */ 167 #define PHY84328_UPDATE_CHECK_DELAY 20 168 #define PHY84328_UPDATE_CHECK_MAX_RETRIES 100 169 170 171 /* I2C related defines */ 172 #define PHY84328_BSC_XFER_MAX 0x1F9 173 #define PHY84328_BSC_WR_MAX 16 174 #define PHY84328_WRITE_START_ADDR 0x8007 175 #define PHY84328_READ_START_ADDR 0x8007 176 #define PHY84328_WR_FREQ_400KHZ 0x0100 177 #define PHY84328_2W_STAT 0x000C 178 #define PHY84328_2W_STAT_IDLE 0x0000 179 #define PHY84328_2W_STAT_COMPLETE 0x0004 180 #define PHY84328_2W_STAT_IN_PRG 0x0008 181 #define PHY84328_2W_STAT_FAIL 0x000C 182 #define PHY84328_BSC_WRITE_OP 0x22 183 #define PHY84328_BSC_READ_OP 0x2 184 #define PHY84328_I2CDEV_WRITE 0x1 185 #define PHY84328_I2CDEV_READ 0x0 186 #define PHY84328_I2C_8BIT 0 187 #define PHY84328_I2C_16BIT 1 188 #define PHY84328_I2C_TEMP_RAM 0xE 189 #define PHY84328_I2C_OP_TYPE(access_type,data_type) \ 190 ((access_type) | ((data_type) << 8)) 191 #define PHY84328_I2C_ACCESS_TYPE(op_type) ((op_type) & 0xff) 192 #define PHY84328_I2C_DATA_TYPE(op_type) (((op_type) >> 8) & 0xff) 193 #define I2CM_IDLE_WAIT_MSEC 350 194 #define I2CM_IDLE_WAIT_CHUNK 10 195 #define I2CM_IDLE_WAIT_COUNT (I2CM_IDLE_WAIT_MSEC / I2CM_IDLE_WAIT_CHUNK) 196 197 198 199 #define PHY84328_ALL_LANES 0x000f 200 201 #define PHY84328_PREEMPH_CTRL_FORCE_SHIFT 15 202 #define PHY84328_PREEMPH_CTRL_POST_TAP_SHIFT 10 203 #define PHY84328_PREEMPH_CTRL_MAIN_TAP_SHIFT 4 204 #define PHY84328_PREEMPH_CTRL_PRE_TAP_SHIFT 0 205 206 #define PHY84328_PREEMPH_FORCE_GET(_val) (((_val) >> PHY84328_PREEMPH_CTRL_FORCE_SHIFT) & 0x1) 207 #define PHY84328_PREEMPH_POST_TAP_GET(_val) (((_val) >> PHY84328_PREEMPH_CTRL_POST_TAP_SHIFT) & 0xf) 208 #define PHY84328_PREEMPH_MAIN_TAP_GET(_val) (((_val) >> PHY84328_PREEMPH_CTRL_MAIN_TAP_SHIFT) & 0x1f) 209 #define PHY84328_PREEMPH_PRE_TAP_GET(_val) (((_val) >> PHY84328_PREEMPH_CTRL_PRE_TAP_SHIFT) & 0x7) 210 211 #define PHY84328_PREEMPH_FORCE_SET(_val) (((_val) & 1) << PHY84328_PREEMPH_CTRL_FORCE_SHIFT) 212 #define PHY84328_PREEMPH_POST_TAP_SET(_val) (((_val) & 0xf) << PHY84328_PREEMPH_CTRL_POST_TAP_SHIFT) 213 #define PHY84328_PREEMPH_MAIN_TAP_SET(_val) (((_val) & 0x1f) << PHY84328_PREEMPH_CTRL_MAIN_TAP_SHIFT) 214 #define PHY84328_PREEMPH_PRE_TAP_SET(_val) (((_val) & 7) << PHY84328_PREEMPH_CTRL_PRE_TAP_SHIFT) 215 216 /* CL73 pause advertisement */ 217 #define CL73_AN_ADV_PAUSE (1 << 10) 218 #define CL73_AN_ADV_ASYM_PAUSE (1 << 11) 219 220 /* Multicore port */ 221 #define PHY84328_MAX_CORES 3 222 #define PHY84328_CORE_STATE_SIZE (sizeof(phy_ctrl_t) + sizeof(phy84328_dev_desc_t)) 223 224 #define PHY84328_MULTI_CORE_MODE(_pc) ((_pc)->phy_mode == PHYCTRL_MULTI_CORE_PORT) 225 #define PHY84328_VALID_CORE(_c) ((_c) < PHY84328_MAX_CORES) 226 #define PHY84328_CORES(_u, _p) ((SOC_INFO((_u)).port_num_lanes[(_p)] + 3) / 4) 227 #define PHY84328_CORE_PC(_pc, _c) (phy_ctrl_t *) \ 228 (((uint8 *)(_pc)) + (PHY84328_CORE_STATE_SIZE * (_c))) 229 230 #define PHY84328_CORE_STATE_SET(unit, port, core, pc) \ 231 do {\ 232 EXT_PHY_SW_STATE(unit, port) = PHY84328_CORE_PC(pc, core);\ 233 if (core > 0) { \ 234 (PHY84328_CORE_PC(pc, core))->flags = (pc)->flags;\ 235 } \ 236 } while (0) 237 238 #define PHY84328_CALL_SET(_u, _p, _func) \ 239 do { \ 240 int _rv = SOC_E_NONE; \ 241 phy_ctrl_t *_pc = EXT_PHY_SW_STATE((_u), (_p)); \ 242 if (DBG_FLAGS(_pc) & PHY84328_DBG_F_API_SET) { \ 243 LOG_INFO(BSL_LS_SOC_PHY,\ 244 (BSL_META_U(unit,\ 245 "%s(%d, %d)\n"), FUNCTION_NAME(), (_u), (_p))); \ 246 } \ 247 if (! PHY84328_MULTI_CORE_MODE(_pc)) { \ 248 _rv = (_func); \ 249 } else { \ 250 int _c, _ac; \ 251 _ac = PHY84328_CORES((_u), (_p)); \ 252 for (_c = 0; _c < _ac; _c++) { \ 253 PHY84328_CORE_STATE_SET((_u), (_p), _c, _pc); \ 254 _rv = (_func); \ 255 if (_rv != SOC_E_NONE) { \ 256 break; \ 257 } \ 258 } \ 259 PHY84328_CORE_STATE_SET((_u), (_p), 0, _pc); \ 260 } \ 261 return _rv; \ 262 } while (0) 263 264 265 #define PHY84328_CALL_GET(_u, _p, _func, _v, _pv) \ 266 do { \ 267 int _rv = SOC_E_NONE; \ 268 phy_ctrl_t *_pc = EXT_PHY_SW_STATE((_u), (_p)); \ 269 if (DBG_FLAGS(_pc) & PHY84328_DBG_F_API_GET) { \ 270 LOG_INFO(BSL_LS_SOC_PHY,\ 271 (BSL_META_U(unit,\ 272 "%s(%d, %d)\n"), FUNCTION_NAME(), (_u), (_p))); \ 273 } \ 274 if (! PHY84328_MULTI_CORE_MODE(_pc)) { \ 275 _rv = (_func); \ 276 } else { \ 277 int _c, _ac; \ 278 _ac = PHY84328_CORES((_u), (_p)); \ 279 for (_c = 0; _c < _ac; _c++) { \ 280 PHY84328_CORE_STATE_SET((_u), (_p), _c, _pc); \ 281 _rv = (_func); \ 282 if (_rv != SOC_E_NONE) { \ 283 break; \ 284 } \ 285 if (_c == 0) { \ 286 (_pv) = *(_v); \ 287 } else if (*(_v) != (_pv)) { \ 288 LOG_ERROR(BSL_LS_SOC_PHY,\ 289 (BSL_META_U(unit,\ 290 "84328 %s val does not match for all cores: u=%d p=%d\n"), \ 291 FUNCTION_NAME(), (_u), (_p))); \ 292 } \ 293 } \ 294 PHY84328_CORE_STATE_SET((_u), (_p), 0, _pc); \ 295 } \ 296 return _rv; \ 297 } while (0) 298 299 300 #define PHY_84328_MICRO_PAUSE(_u, _p, _s) \ 301 do { \ 302 phy_ctrl_t *_pc; \ 303 _pc = EXT_PHY_SW_STATE((_u), (_p)); \ 304 if (DEVREV(_pc) == 0x00a0) { \ 305 _phy_84328_micro_pause((_u), (_p), (_s)); \ 306 } \ 307 } while (0) 308 309 #define PHY_84328_MICRO_RESUME(_u, _p) \ 310 do { \ 311 phy_ctrl_t *_pc; \ 312 _pc = EXT_PHY_SW_STATE((_u), (_p)); \ 313 if (DEVREV(_pc) == 0x00a0) { \ 314 _phy_84328_micro_resume((_u), (_p)); \ 315 } \ 316 } while (0) 317 318 /* 319 * PHY system interface types 320 * These values are used when configuring system side interface with spn_PHY_SYS_INTERFACE 321 * Always add at the end but never change the order!! Adding also requires updating 322 * grog documentation 323 */ 324 enum { 325 PHY_SYSTEM_INTERFACE_DFLT = 0, 326 PHY_SYSTEM_INTERFACE_KX = 1, 327 PHY_SYSTEM_INTERFACE_KR = 2, 328 PHY_SYSTEM_INTERFACE_SR = 3, 329 PHY_SYSTEM_INTERFACE_LR = 4, 330 PHY_SYSTEM_INTERFACE_CR = 5, /* System side as XFI-DFE, or system side DAC */ 331 PHY_SYSTEM_INTERFACE_KR4 = 6, 332 PHY_SYSTEM_INTERFACE_SR4 = 7, 333 PHY_SYSTEM_INTERFACE_LR4 = 8, 334 PHY_SYSTEM_INTERFACE_CR4 = 9, /* System side as XLAUI-DFE, or system side DAC */ 335 PHY_SYSTEM_INTERFACE_XFI = 10, 336 PHY_SYSTEM_INTERFACE_XLAUI = 11, 337 PHY_SYSTEM_INTERFACE_INVALID /* must be last */ 338 }; 339 340 soc_port_if_t phy_sys_to_port_if[] = { 341 0, /* PHY_SYSTEM_INTERFACE_DFLT */ 342 SOC_PORT_IF_KX, /* PHY_SYSTEM_INTERFACE_KX */ 343 SOC_PORT_IF_KR, /* PHY_SYSTEM_INTERFACE_KR */ 344 SOC_PORT_IF_SR, /* PHY_SYSTEM_INTERFACE_SR */ 345 SOC_PORT_IF_LR, /* PHY_SYSTEM_INTERFACE_LR */ 346 SOC_PORT_IF_CR, /* PHY_SYSTEM_INTERFACE_CR */ 347 SOC_PORT_IF_KR4, /* PHY_SYSTEM_INTERFACE_KR4 */ 348 SOC_PORT_IF_SR4, /* PHY_SYSTEM_INTERFACE_SR4 */ 349 SOC_PORT_IF_LR4, /* PHY_SYSTEM_INTERFACE_LR4 */ 350 SOC_PORT_IF_CR4, /* PHY_SYSTEM_INTERFACE_CR4 */ 351 SOC_PORT_IF_XFI, /* PHY_SYSTEM_INTERFACE_XFI */ 352 SOC_PORT_IF_XLAUI, /* PHY_SYSTEM_INTERFACE_XLAUI */ 353 }; 354 355 /* interface params */ 356 typedef struct phy84328_intf_cfg { 357 int speed; 358 soc_port_if_t type; 359 } phy84328_intf_cfg_t; 360 361 typedef enum { 362 PHY84328_DATAPATH_20, 363 PHY84328_DATAPATH_4_DEPTH1, 364 PHY84328_DATAPATH_4_DEPTH2 365 } phy84328_datapath_t; 366 367 typedef struct phy84328_counters { 368 uint32 intf_updates; 369 uint32 link_down; 370 uint32 retry_serdes_link; 371 uint32 speed_chk_err; 372 uint32 intf_chk_err; 373 uint32 side_sel_err; 374 uint32 no_cdr; 375 uint32 micro_nopause; 376 } phy84328_counters_t; 377 378 /* 379 * Software RX LOS (Loss of Signal) WAR 380 * The workaround handles conditions when loss of signal is not reliably 381 * detected. A typical scenario is when the cable is still plugged to a module but 382 * the link partner has disable its tx, in which case some modules do not correctly 383 * report loss of signal. 384 */ 385 typedef enum { 386 PHY84328_SW_RX_LOS_RESET, 387 PHY84328_SW_RX_LOS_INITIAL_LINK, 388 PHY84328_SW_RX_LOS_LINK, 389 PHY84328_SW_RX_LOS_START_TIMER, 390 PHY84328_SW_RX_LOS_RX_RESTART, 391 PHY84328_SW_RX_LOS_IDLE 392 } phy84328_sw_rx_los_states_t; 393 394 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 395 const static char *sw_rx_los_state_names[] = { 396 "RESET", 397 "INITIAL_LINK", 398 "LINK", 399 "START_TIMER", 400 "RX_RESTART", 401 "IDLE" 402 }; 403 #endif /* BROADCOM_DEBUG || DEBUG_PRINT */ 404 405 typedef struct { 406 uint8 cfg_enable; /* configured with ph control or not */ 407 uint8 cur_enable; /* currently enabled or not */ 408 uint8 sys_link; 409 uint8 link_no_pcs; 410 uint8 link_status; 411 uint8 fault_report_dis; 412 uint8 ls_ticks; 413 uint32 restarts; 414 mac_driver_t *macd; 415 phy84328_sw_rx_los_states_t state; 416 } phy84328_sw_rx_los_t; 417 418 #define PHY84328_LINK_DEBOUNCE 20 419 typedef struct { 420 int cur_enable; 421 int cfg_enable; 422 int debounce; 423 } phy84328_link_mon_t; 424 425 typedef struct { 426 int enable; 427 int count; /* resume only if count==0 */ 428 } phy84328_micro_ctrl_t; 429 430 #define PHY84328_NUM_LANES 4 431 432 #define PHY84328_DBG_F_REG (1 << 0) 433 #define PHY84328_DBG_F_EYE (1 << 1) 434 #define PHY84328_DBG_F_DWLD (1 << 3) 435 #define PHY84328_DBG_F_API_SET (1 << 4) 436 #define PHY84328_DBG_F_API_GET (1 << 5) 437 438 typedef struct { 439 uint32 devid; 440 uint16 devrev; 441 int core_num; 442 uint32 dbg_flags; 443 int p2l_map[PHY84328_NUM_LANES]; /* index: physical lane, array element: */ 444 phy84328_intf_cfg_t line_intf; 445 phy84328_intf_cfg_t sys_intf; 446 phy84328_sw_rx_los_t sw_rx_los; /* sw_rx_los war */ 447 int fw_rx_los; /* rx LOS handled by firmware */ 448 phy84328_counters_t counters; 449 int cur_link; 450 uint16 pol_tx_cfg; 451 uint16 pol_rx_cfg; 452 int mod_auto_detect; /* module auto detect enabled */ 453 phy84328_datapath_t cfg_datapath; 454 phy84328_datapath_t cur_datapath; 455 phy84328_link_mon_t link_mon; 456 int sys_forced_cl72; 457 int an_en; 458 int force_20bit; 459 int sync_init; 460 int int_phy_re_en; 461 soc_timeout_t sync_to; 462 uint16 logical_lane0; 463 int update_config; 464 int bypass_ss_tuning; 465 phy84328_micro_ctrl_t micro_ctrl; 466 int cfg_sys_intf; 467 int port_enable_delay; 468 } phy84328_dev_desc_t; 469 470 #define DEVID(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->devid) 471 #define DEVREV(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->devrev) 472 #define CORE_NUM(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->core_num) 473 #define DBG_FLAGS(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->dbg_flags) 474 #define P2L_MAP(_pc,_ix) (((phy84328_dev_desc_t *)((_pc) + 1))->p2l_map[(_ix)]) 475 #define LINE_INTF(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->line_intf) 476 #define SYS_INTF(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->sys_intf) 477 #define SW_RX_LOS(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->sw_rx_los) 478 #define FW_RX_LOS(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->fw_rx_los) 479 #define COUNTERS(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->counters) 480 #define CUR_LINK(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->cur_link) 481 #define POL_TX_CFG(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->pol_tx_cfg) 482 #define POL_RX_CFG(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->pol_rx_cfg) 483 #define MOD_AUTO_DETECT(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->mod_auto_detect) 484 #define CFG_DATAPATH(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->cfg_datapath) 485 #define CUR_DATAPATH(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->cur_datapath) 486 #define SYS_FORCED_CL72(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->sys_forced_cl72) 487 #define AN_EN(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->an_en) 488 #define FORCE_20BIT(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->force_20bit) 489 #define FORCE_20BIT_LB (1 << 0) 490 #define FORCE_20BIT_AN (1 << 1) 491 492 #define LINK_MON(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->link_mon) 493 #define SYNC_INIT(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->sync_init) 494 #define SYNC_TO(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->sync_to) 495 #define INT_PHY_RE_EN(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->int_phy_re_en) 496 #define LOGICAL_LANE0(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->logical_lane0) 497 #define BYPASS_SS_TUNING(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->bypass_ss_tuning) 498 #define MICRO_CTRL(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->micro_ctrl) 499 #define CFG_SYS_INTF(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->cfg_sys_intf) 500 #define PORT_ENABLE_DELAY(_pc) (((phy84328_dev_desc_t *)((_pc) + 1))->port_enable_delay) 501 502 /* Polarity config */ 503 #define POL_CONFIG_ALL_LANES 1 504 #define POL_CONFIG_LANE_WIDTH 0x4 505 #define POL_CONFIG_LANE_MASK(_ln) (0xf << ((_ln) * POL_CONFIG_LANE_WIDTH)) 506 /* 507 * When a port is being flexed between 40G->10G, 508 * the polarity config syntax can be in 509 * 40G syntax for first lane, so there is a need to parse 510 * both 10G and 40G polarity config syntax in 10G. 511 */ 512 #define PHY84328_LN(_pc) ((_pc)->phy_id & 0x3) 513 #define PHY84328_POL_MASK(_pc) POL_CONFIG_LANE_MASK(PHY84328_LN(_pc)) 514 #define PHY84328_10G_POL_CFG_GET(_pc, _pol) \ 515 (((_pol) == POL_CONFIG_ALL_LANES) || \ 516 (((_pol) & PHY84328_POL_MASK(_pc)) == PHY84328_POL_MASK(_pc))) 517 518 519 typedef enum { 520 PHY84328_INTF_SIDE_LINE, 521 PHY84328_INTF_SIDE_SYS 522 } phy84328_intf_side_t; 523 524 525 STATIC int _phy_84328_chip_id_get(int unit, soc_port_t port, phy_ctrl_t *pc, uint32 *chip_id); 526 /* interface primitives */ 527 STATIC int _phy_84328_intf_is_single_port(soc_port_if_t intf_type); 528 STATIC int _phy_84328_intf_is_quad_port(soc_port_if_t intf_type); 529 STATIC int _phy_84328_intf_type_reg_get(int unit, soc_port_t port, soc_port_if_t intf_type, 530 phy84328_intf_side_t side, uint16 *reg_data, uint16 *reg_mask); 531 STATIC int _phy_84328_intf_update(int unit, soc_port_t port, uint16 reg_data, uint16 reg_mask); 532 STATIC int _phy_84328_intf_line_sys_params_get(int unit, soc_port_t port); 533 STATIC int _phy_84328_intf_line_sys_update(int unit, soc_port_t port); 534 STATIC int _phy_84328_intf_line_sys_init(int unit, soc_port_t port); 535 STATIC int _phy_84328_intf_datapath_update(int unit, soc_port_t port); 536 STATIC int _phy_84328_intf_speed_reg_get(int unit, soc_port_t port, int speed, 537 uint16 *reg_data, uint16 *reg_mask); 538 539 STATIC int _phy_84328_intf_link_get(int unit, soc_port_t port, uint16 *link); 540 STATIC int _phy_84328_intf_print(int unit, soc_port_t port, const char *msg); 541 STATIC void _phy_84328_intf_side_regs_select(int unit, soc_port_t port, phy84328_intf_side_t side); 542 STATIC phy84328_intf_side_t _phy_84328_intf_side_regs_get(int unit, soc_port_t); 543 STATIC int _phy_84328_intf_datapath_reg_get(int unit, soc_port_t port, phy84328_datapath_t datapath, 544 uint16 *reg_data, uint16 *reg_mask); 545 STATIC int _phy_84328_intf_line_forced(int unit, soc_port_t port, soc_port_if_t intf_type); 546 STATIC int _phy_84328_config_devid(int unit,soc_port_t port, phy_ctrl_t *pc, uint32 *devid); 547 STATIC int _phy_84328_speed_set(int unit, soc_port_t port, int speed); 548 STATIC int _phy_84328_polarity_flip(int unit, soc_port_t port, uint16 cfg_tx_pol, uint16 cfg_rx_pol); 549 STATIC int _phy_84328_intf_type_set(int unit, soc_port_t port, soc_port_if_t pif, int must_update); 550 STATIC int _phy_84328_txmode_manual_set(int unit, soc_port_t port, phy84328_intf_side_t side, int set); 551 STATIC int _phy_84328_tx_config(int unit, soc_port_t port); 552 STATIC int _phy_84328_tx_enable(int unit, soc_port_t port, phy84328_intf_side_t side, int enable); 553 STATIC int _phy_84328_sw_rx_los_pause(int unit, soc_port_t, int enable); 554 STATIC int _phy_84328_link_mon_pause(int unit, soc_port_t, int enable); 555 STATIC int _phy_84328_control_tx_driver_set(int unit, soc_port_t port, soc_phy_control_t type, 556 phy84328_intf_side_t side, uint32 value); 557 STATIC int phy_84328_control_port_set(int unit, soc_port_t port, soc_phy_control_t type, uint32 value); 558 STATIC int phy_84328_control_port_get(int unit, soc_port_t port, soc_phy_control_t type, uint32 *value); 559 560 /* Debug support for selective tracing mdio by this driver */ 561 /* #define PHY84328_MDIO_TRACING 1 */ 562 #ifdef PHY84328_MDIO_TRACING 563 STATIC int _phy_84328_dbg_read(int unit, phy_ctrl_t *pc, uint32 addr, uint16 *data); 564 STATIC int _phy_84328_dbg_write(int unit, phy_ctrl_t *pc, uint32 addr, uint16 data); 565 STATIC int _phy_84328_dbg_modify(int unit, phy_ctrl_t *pc, uint32 addr, uint16 data, uint16 mask); 566 567 #undef READ_PHY_REG 568 #define READ_PHY_REG(_unit, _pc, _addr, _value) \ 569 ((_phy_84328_dbg_read)((_pc->unit), _pc, (_addr), (_value))) 570 #undef WRITE_PHY_REG 571 #define WRITE_PHY_REG(_unit, _pc, _addr, _value) \ 572 ((_phy_84328_dbg_write)((_pc->unit), _pc, (_addr), (_value))) 573 #undef MODIFY_PHY_REG 574 #define MODIFY_PHY_REG(_unit, _pc, _addr, _data, _mask) \ 575 (_phy_84328_dbg_modify((_unit), (_pc), (_addr), (_data), (_mask))) 576 #endif /* PHY84328_MDIO_TRACING */ 577 578 extern unsigned char phy84328_ucode_bin[]; 579 extern unsigned int phy84328_ucode_bin_len; 580 extern unsigned char phy84328B0_ucode_bin[]; 581 extern unsigned int phy84328B0_ucode_bin_len; 582 static char *dev_name_84328_a0 = "BCM84328_A0"; 583 static char *dev_name_84328 = "BCM84328"; 584 static char *dev_name_84324 = "BCM84324"; 585 static char *dev_name_84088 = "BCM84088"; 586 static char *dev_name_84024 = "BCM84024"; 587 588 static const char *phy84328_intf_names[] = SOC_PORT_IF_NAMES_INITIALIZER; 589 590 /* callback to deliever the firmware by application 591 * return value: TRUE successfully delivered 592 * FALSE fail to deliver 593 * 594 * Example: 595 * 596 * int user_firmware_send (int unit,int port,int flag,unsigned char **data,int *len) 597 * { 598 * *data = phy84328_ucode_bin; 599 * *len = phy84328_ucode_bin_len; 600 * return TRUE; 601 * } 602 * Then initialize the function pointer before the BCM port initialization: 603 * phy_84328_uc_firmware_hook = user_firmware_send; 604 */ 605 int (*phy_84328_uc_firmware_hook)( 606 int unit, /* switch number */ 607 int port, /* port number */ 608 int flag, /* any information need to ba passed. Not used for now*/ 609 unsigned char **addr, /* starting address of delivered firmware */ 610 int *len /* length of the firmware */ 611 ) = NULL; 612 613 STATIC int 614 _phy_84328_chip_id_get(int unit, soc_port_t port, phy_ctrl_t *pc, uint32 *chip_id) 615 { 616 int rv = SOC_E_NONE; 617 618 uint16 chip_id_lsb = 0, chip_id_msb = 0; 619 620 *chip_id = 0; 621 622 SOC_IF_ERROR_RETURN( 623 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_CHIP_ID0_REGISTER, &chip_id_lsb)); 624 SOC_IF_ERROR_RETURN( 625 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_CHIP_ID1_REGISTER, &chip_id_msb)); 626 627 if (chip_id_msb == 0x8) { 628 if (chip_id_lsb == 0x4328) { 629 *chip_id = PHY84328_ID_84328; 630 } else if (chip_id_lsb == 0x4324) { 631 *chip_id = PHY84328_ID_84324; 632 } else if (chip_id_lsb == 0x4088) { 633 *chip_id = PHY84328_ID_84088; 634 } else if(chip_id_lsb == 0x4024) { 635 *chip_id = PHY84328_ID_84024; 636 } else { 637 LOG_ERROR(BSL_LS_SOC_PHY, 638 (BSL_META_U(unit, 639 "PHY84328 bad chip id: u=%d p=%d chipid %x%x\n"), 640 unit, port, chip_id_msb, chip_id_lsb)); 641 rv = SOC_E_BADID; 642 } 643 } 644 return rv; 645 } 646 647 STATIC void 648 _phy_84328_intf_side_regs_select(int unit, soc_port_t port, phy84328_intf_side_t side) 649 { 650 int rv; 651 uint16 data, mask; 652 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 653 654 assert((side == PHY84328_INTF_SIDE_SYS) || (side == PHY84328_INTF_SIDE_LINE)); 655 data = (side == PHY84328_INTF_SIDE_SYS) ? (1 << PHY84328_DEV1_XPMD_REGS_SEL_SELECT_SYS_REGISTERS_SHIFT) : 0; 656 mask = PHY84328_DEV1_XPMD_REGS_SEL_SELECT_SYS_REGISTERS_MASK; 657 658 /* configure all ports */ 659 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_XPMD_REGS_SEL, data, mask); 660 if (SOC_FAILURE(rv)) { 661 phy84328_counters_t *counters = &(COUNTERS(pc)); 662 counters->side_sel_err++; 663 } 664 } 665 666 STATIC phy84328_intf_side_t 667 _phy_84328_intf_side_regs_get(int unit, soc_port_t port) 668 { 669 int rv; 670 uint16 data; 671 phy84328_intf_side_t side = PHY84328_INTF_SIDE_LINE; 672 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 673 674 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_XPMD_REGS_SEL, &data); 675 if (rv == SOC_E_NONE) { 676 side = ((data & PHY84328_DEV1_XPMD_REGS_SEL_SELECT_SYS_REGISTERS_MASK) == 677 (1 << PHY84328_DEV1_XPMD_REGS_SEL_SELECT_SYS_REGISTERS_SHIFT)) ? 678 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE; 679 } 680 return side; 681 } 682 683 STATIC int 684 _phy_84328_intf_print(int unit, soc_port_t port, const char *msg) 685 { 686 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 687 phy_ctrl_t *pc; 688 phy84328_intf_cfg_t *line_intf, *sys_intf; 689 690 pc = EXT_PHY_SW_STATE(unit, port); 691 line_intf = &(LINE_INTF(pc)); 692 sys_intf = &(SYS_INTF(pc)); 693 694 LOG_INFO(BSL_LS_SOC_PHY, 695 (BSL_META_U(unit, 696 "%s: "), msg)); 697 LOG_INFO(BSL_LS_SOC_PHY, 698 (BSL_META_U(unit, 699 "[LINE:intf=%s,speed=%d], "), 700 phy84328_intf_names[line_intf->type], line_intf->speed)); 701 LOG_INFO(BSL_LS_SOC_PHY, 702 (BSL_META_U(unit, 703 "[SYS :intf=%s,speed=%d]\n"), 704 phy84328_intf_names[sys_intf->type], sys_intf->speed)); 705 #endif /* BROADCOM_DEBUG || DEBUG_PRINT */ 706 707 return SOC_E_NONE; 708 } 709 710 STATIC int 711 _phy_84328_intf_is_single_port(soc_port_if_t intf_type) 712 { 713 int rv; 714 715 switch (intf_type) { 716 case SOC_PORT_IF_CR4: 717 case SOC_PORT_IF_KR4: 718 case SOC_PORT_IF_XLAUI: 719 case SOC_PORT_IF_LR4: 720 case SOC_PORT_IF_SR4: 721 case SOC_PORT_IF_CAUI: 722 /*****CR10 TBD **** 723 case SOC_PORT_IF_CR10: 724 *****CR10 TBD ****/ 725 rv = TRUE; 726 break; 727 default: 728 rv = FALSE; 729 } 730 return rv; 731 } 732 733 STATIC int 734 _phy_84328_intf_is_quad_port(soc_port_if_t intf_type) 735 { 736 int rv; 737 738 switch (intf_type) { 739 case SOC_PORT_IF_SR: 740 case SOC_PORT_IF_CR: 741 case SOC_PORT_IF_KR: 742 case SOC_PORT_IF_XFI: 743 case SOC_PORT_IF_SFI: 744 case SOC_PORT_IF_LR: 745 case SOC_PORT_IF_ZR: 746 case SOC_PORT_IF_KX: 747 case SOC_PORT_IF_GMII: 748 case SOC_PORT_IF_SGMII: 749 rv = TRUE; 750 break; 751 default: 752 rv = FALSE; 753 } 754 return rv; 755 } 756 757 STATIC int 758 _phy_84328_intf_type_10000(soc_port_if_t intf_type) 759 { 760 int rv; 761 762 switch (intf_type) { 763 case SOC_PORT_IF_SR: 764 case SOC_PORT_IF_CR: 765 case SOC_PORT_IF_KR: 766 case SOC_PORT_IF_ZR: 767 case SOC_PORT_IF_XFI: 768 case SOC_PORT_IF_SFI: 769 case SOC_PORT_IF_LR: 770 rv = TRUE; 771 break; 772 default: 773 rv = FALSE; 774 } 775 return rv; 776 } 777 STATIC int 778 _phy_84328_intf_type_1000(soc_port_if_t intf_type) 779 { 780 int rv; 781 782 switch (intf_type) { 783 case SOC_PORT_IF_KX: 784 case SOC_PORT_IF_GMII: 785 case SOC_PORT_IF_SGMII: 786 rv = TRUE; 787 break; 788 default: 789 rv = FALSE; 790 } 791 return rv; 792 } 793 794 /* 795 * Return the settings in gp_register_1 for the line inteface type 796 * 797 * SOC_PORT_IF SPEED GP_REGISTER_1 798 * ------------ ----------- ------------------------------------------- 799 * XFI 10G(1G) OPTICAL 800 * SR 10G(1G) OPTICAL 801 * LR 10G(1G) OPTICAL+LR 802 * CR 10G(1G) OPTICAL+CU 803 * XLAUI 10G(1G) OPTICAL 804 * SR4 40G OPTICAL 805 * LR4 40G(1G) OPTICAL+LR 806 * CR4 40G(1G) OPTICAL+CU 807 * KX 1G BACKPLANE 808 * KR 10G BACKPLANE 809 * KR4 40G BACKPLANE 810 * KR2 20G BACKPLANE 811 * XFI2 20G(1G) OPTICAL 812 * SR2 20G(1G) OPTICAL 813 * CR2 20G OPTICAL+CU 814 */ 815 816 STATIC int 817 _phy_84328_intf_type_reg_get(int unit, soc_port_t port, soc_port_if_t intf_type, 818 phy84328_intf_side_t side, uint16 *reg_data, uint16 *reg_mask) 819 { 820 uint16 data = 0; 821 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 822 823 assert((side == PHY84328_INTF_SIDE_LINE) || (side == PHY84328_INTF_SIDE_SYS)); 824 *reg_data = 0; 825 *reg_mask = 0; 826 827 switch (intf_type) { 828 case SOC_PORT_IF_KX: 829 case SOC_PORT_IF_KR: 830 case SOC_PORT_IF_KR4: 831 if (side == PHY84328_INTF_SIDE_SYS) { 832 data = SYS_FORCED_CL72(pc) ? (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_FORCED_CL72_MODE_SHIFT) : 833 (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_TYPE_SHIFT); 834 } else { 835 /* line side */ 836 data = (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_TYPE_SHIFT); 837 } 838 break; 839 case SOC_PORT_IF_SR: 840 case SOC_PORT_IF_SR4: 841 case SOC_PORT_IF_GMII: 842 case SOC_PORT_IF_SGMII: 843 data = 0; 844 break; 845 case SOC_PORT_IF_ZR: 846 data = (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_LR_MODE_SHIFT) | 847 (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_FORCED_CL72_MODE_SHIFT); 848 break; 849 case SOC_PORT_IF_CR4: 850 /* 851 * If CR4 line side and autoneg enabled, then CR4, otherwise, DAC/XLAUI_DFE 852 */ 853 if (side == PHY84328_INTF_SIDE_LINE) { 854 /* 855 * If CR4 line side and autoneg enabled, then CR4, otherwise, DAC/XLAUI_DFE 856 */ 857 data = (AN_EN(pc)) ? (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_SHIFT) : 858 ((1 << PHY84328_DEV1_GP_REGISTER_1_LINE_FORCED_CL72_MODE_SHIFT) | 859 (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_SHIFT)); 860 } else { 861 /* System side set to XLAUI_DFE */ 862 data = (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_FORCED_CL72_MODE_SHIFT) | 863 (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_CU_TYPE_SHIFT); 864 } 865 break; 866 case SOC_PORT_IF_CR: 867 data = (side == PHY84328_INTF_SIDE_SYS) ? 868 ((1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_FORCED_CL72_MODE_SHIFT) | 869 (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_CU_TYPE_SHIFT)) : 870 (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_SHIFT); 871 break; 872 873 case SOC_PORT_IF_XFI: 874 case SOC_PORT_IF_SFI: 875 case SOC_PORT_IF_XLAUI: 876 case SOC_PORT_IF_CAUI: 877 data = (side == PHY84328_INTF_SIDE_SYS) ? 878 ((1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_LR_MODE_SHIFT) | 879 (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_CU_TYPE_SHIFT)) : 880 ((1 << PHY84328_DEV1_GP_REGISTER_1_LINE_LR_MODE_SHIFT) | 881 (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_SHIFT)); 882 break; 883 case SOC_PORT_IF_LR: 884 case SOC_PORT_IF_LR4: 885 data = (side == PHY84328_INTF_SIDE_SYS) ? 886 (1 << PHY84328_DEV1_GP_REGISTER_1_SYSTEM_LR_MODE_SHIFT) : 887 (1 << PHY84328_DEV1_GP_REGISTER_1_LINE_LR_MODE_SHIFT); 888 break; 889 default: 890 LOG_ERROR(BSL_LS_SOC_PHY, 891 (BSL_META_U(unit, 892 "84328 Unsupported interface: u=%d p=%d\n"), unit, port)); 893 return SOC_E_UNAVAIL; 894 }; 895 896 *reg_data |= (data | PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE); 897 898 if (side == PHY84328_INTF_SIDE_LINE) { 899 *reg_mask |= (PHY84328_DEV1_GP_REGISTER_1_LINE_LR_MODE_MASK | 900 PHY84328_DEV1_GP_REGISTER_1_LINE_FORCED_CL72_MODE_MASK | 901 PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_MASK | 902 PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK | 903 PHY84328_DEV1_GP_REGISTER_1_LINE_TYPE_MASK); 904 905 } else { 906 /* System side mask */ 907 *reg_mask |= (PHY84328_DEV1_GP_REGISTER_1_SYSTEM_LR_MODE_MASK | 908 PHY84328_DEV1_GP_REGISTER_1_SYSTEM_FORCED_CL72_MODE_MASK | 909 PHY84328_DEV1_GP_REGISTER_1_SYSTEM_CU_TYPE_MASK | 910 PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK | 911 PHY84328_DEV1_GP_REGISTER_1_SYSTEM_TYPE_MASK); 912 } 913 LOG_INFO(BSL_LS_SOC_PHY, 914 (BSL_META_U(unit, 915 "84328 intf type register: u=%d, p=%d, reg=%04x/%04x, intf=%d\n"), 916 unit, port, *reg_data, *reg_mask, intf_type)); 917 918 return SOC_E_NONE; 919 } 920 921 922 STATIC int 923 _phy_84328_polarity_redo(int unit, soc_port_t port) 924 { 925 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 926 return _phy_84328_polarity_flip(unit, port, POL_TX_CFG(pc), POL_RX_CFG(pc)); 927 } 928 929 STATIC void 930 _phy_84328_micro_pause(int unit, soc_port_t port, const char *loc) 931 { 932 int rv = SOC_E_NONE; 933 uint16 data, mask; 934 int checks; 935 uint16 csr; 936 uint16 saved_side; 937 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 938 phy84328_micro_ctrl_t *micro_ctrl = &(MICRO_CTRL(pc)); 939 phy84328_counters_t *counters = &(COUNTERS(pc)); 940 941 if (!micro_ctrl->enable) { 942 return; 943 } 944 945 /* Access line side registers */ 946 saved_side = _phy_84328_intf_side_regs_get(unit, port); 947 if (saved_side == PHY84328_INTF_SIDE_SYS) { 948 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 949 } 950 951 micro_ctrl->count++; 952 /* Quiet micro */ 953 data = 0; 954 mask = 0xff00; 955 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, data, mask); 956 if (rv != SOC_E_NONE) { 957 goto fail; 958 } 959 sal_udelay(500); 960 checks = 0; 961 while (checks < 1000) { 962 /* Make sure micro really paused */ 963 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_2, &data); 964 if (rv != SOC_E_NONE) { 965 goto fail; 966 } 967 if ((data & mask) == 0) { 968 break; 969 } 970 sal_udelay(100); 971 checks++; 972 } 973 if (data & mask) { 974 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, &csr); 975 if (rv != SOC_E_NONE) { 976 goto fail; 977 } 978 LOG_INFO(BSL_LS_SOC_PHY, 979 (BSL_META_U(unit, 980 "84328 microcode did not pause in %s: " 981 "u=%d p%d 1.ca18/1.ca19=%04x/%04x checks=%d\n"), 982 loc, unit, port, csr, data, checks)); 983 counters->micro_nopause++; 984 } 985 986 fail: 987 if (saved_side != PHY84328_INTF_SIDE_LINE) { 988 _phy_84328_intf_side_regs_select(unit, port, saved_side); 989 } 990 return; 991 } 992 993 STATIC void 994 _phy_84328_micro_resume(int unit, soc_port_t port) 995 { 996 phy84328_intf_side_t saved_side; 997 int rv = SOC_E_NONE; 998 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 999 phy84328_micro_ctrl_t *micro_ctrl = &(MICRO_CTRL(pc)); 1000 1001 if (!micro_ctrl->enable) { 1002 return; 1003 } 1004 1005 /* Access line side registers */ 1006 saved_side = _phy_84328_intf_side_regs_get(unit, port); 1007 if (saved_side == PHY84328_INTF_SIDE_SYS) { 1008 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1009 } 1010 1011 micro_ctrl->count--; 1012 if (micro_ctrl->count <= 0) { 1013 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, 1014 0xff00, 0xff00); 1015 if (rv != SOC_E_NONE) { 1016 goto fail; 1017 } 1018 if (micro_ctrl->count < 0) { 1019 LOG_VERBOSE(BSL_LS_SOC_PHY, 1020 (BSL_META_U(unit, 1021 "84328 unmatched micro resume\n"))); 1022 micro_ctrl->count = 0;; 1023 } 1024 } 1025 1026 fail: 1027 if (saved_side != PHY84328_INTF_SIDE_LINE) { 1028 _phy_84328_intf_side_regs_select(unit, port, saved_side); 1029 } 1030 return; 1031 } 1032 1033 STATIC int 1034 _phy_84328_config_update(int unit, soc_port_t port) 1035 { 1036 int rv; 1037 phy84328_datapath_t save_dp; 1038 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1039 1040 PHY_84328_MICRO_PAUSE(unit, port, "config update"); 1041 1042 SOC_IF_ERROR_RETURN(_phy_84328_tx_config(unit, port)); 1043 1044 save_dp = CUR_DATAPATH(pc); 1045 CUR_DATAPATH(pc) = PHY84328_DATAPATH_20; 1046 rv = _phy_84328_polarity_redo(unit, port); 1047 if (rv != SOC_E_NONE) { 1048 LOG_ERROR(BSL_LS_SOC_PHY, 1049 (BSL_META_U(unit, 1050 "84328 failed updating config: u=%d port=%d\n"), unit, port)); 1051 } 1052 1053 if (save_dp != PHY84328_DATAPATH_20) { 1054 CUR_DATAPATH(pc) = PHY84328_DATAPATH_4_DEPTH1; 1055 rv = _phy_84328_polarity_redo(unit, port); 1056 if (rv != SOC_E_NONE) { 1057 LOG_ERROR(BSL_LS_SOC_PHY, 1058 (BSL_META_U(unit, 1059 "84328 failed updating config: u=%d port=%d\n"), unit, port)); 1060 } 1061 } 1062 1063 if (save_dp != CUR_DATAPATH(pc)) { 1064 CUR_DATAPATH(pc) = save_dp; 1065 } 1066 1067 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 1068 /* Bypass steady state tuning */ 1069 if (BYPASS_SS_TUNING(pc)) { 1070 SOC_IF_ERROR_RETURN( 1071 MODIFY_PHY84328_MMF_PMA_PMD_REG( 1072 unit, pc, PHY84328_DEV1_TUNING_STATE_BYPASS, 1073 PHY84328_DEV1_TUNING_STATE_BYPASS_BYPASS_STEADY_STATE_TUNING_MASK, 1074 PHY84328_DEV1_TUNING_STATE_BYPASS_BYPASS_STEADY_STATE_TUNING_MASK)); 1075 } else { 1076 SOC_IF_ERROR_RETURN( 1077 MODIFY_PHY84328_MMF_PMA_PMD_REG( 1078 unit, pc, PHY84328_DEV1_TUNING_STATE_BYPASS, 1079 0, 1080 PHY84328_DEV1_TUNING_STATE_BYPASS_BYPASS_STEADY_STATE_TUNING_MASK)); 1081 } 1082 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1083 1084 PHY_84328_MICRO_RESUME(unit, port); 1085 1086 return SOC_E_NONE; 1087 } 1088 1089 /* 1090 * Updates are done to GP_REGISTER_1 which are line side registers only, ie. no 1091 * system side instances of these registers 1092 */ 1093 STATIC int 1094 _phy_84328_intf_update(int unit, soc_port_t port, uint16 reg_data, uint16 reg_mask) 1095 { 1096 uint16 ucode_csr_bef = 0, ucode_csr = 0, drv_csr = 0; 1097 phy84328_intf_side_t saved_side; 1098 soc_timeout_t to; 1099 int rv = SOC_E_NONE; 1100 uint32 checks; 1101 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1102 phy84328_counters_t *counters = &(COUNTERS(pc)); 1103 1104 /* Access line side registers */ 1105 saved_side = _phy_84328_intf_side_regs_get(unit, port); 1106 if (saved_side == PHY84328_INTF_SIDE_SYS) { 1107 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1108 } 1109 1110 /* Make sure ucode has acked */ 1111 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_3, &ucode_csr_bef); 1112 if (SOC_FAILURE(rv)) { 1113 LOG_ERROR(BSL_LS_SOC_PHY, 1114 (BSL_META_U(unit, 1115 "84328 failed reading ucode csr: u=%d p=%d err=%d\n"), 1116 unit, port, rv)); 1117 1118 goto fail; 1119 } 1120 if ((ucode_csr_bef & PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) == 1121 PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) { 1122 /* Cmd active and ucode acked, so let ucode know drv saw ack */ 1123 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, 1124 0, PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK); 1125 if (SOC_FAILURE(rv)) { 1126 LOG_ERROR(BSL_LS_SOC_PHY, 1127 (BSL_META_U(unit, 1128 "84328 failed clearing ack: u=%d p=%d err=%d\n"), 1129 unit, port, rv)); 1130 goto fail; 1131 } 1132 /* Wait for ucode to CTS */ 1133 soc_timeout_init(&to, 1000000, 0); 1134 while (!soc_timeout_check(&to)) { 1135 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_3, &ucode_csr); 1136 if (SOC_FAILURE(rv)) { 1137 LOG_ERROR(BSL_LS_SOC_PHY, 1138 (BSL_META_U(unit, 1139 "84328 failed reading ucode csr: u=%d p=%d err=%d\n"), 1140 unit, port, rv)); 1141 goto fail; 1142 } 1143 if ((ucode_csr & PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) == 0) { 1144 break; 1145 } 1146 } 1147 if ((ucode_csr & PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) != 0) { 1148 (void) READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, &drv_csr); 1149 LOG_ERROR(BSL_LS_SOC_PHY, 1150 (BSL_META_U(unit, 1151 "84328 ucode failed to clear to send: u=%d p=%d 1.%04x=%04x 1.%04x=%04x(%04x)\n"), 1152 unit, port, 1153 PHY84328_DEV1_GP_REGISTER_1, drv_csr, 1154 PHY84328_DEV1_GP_REGISTER_3, ucode_csr, ucode_csr_bef)); 1155 rv = SOC_E_TIMEOUT; 1156 goto fail; 1157 } 1158 } 1159 1160 LOG_INFO(BSL_LS_SOC_PHY, 1161 (BSL_META_U(unit, 1162 "84328 intf update register: u=%d, p=%d, 1.%04x=%04x/%04x ucode_csr=%04x\n"), 1163 unit, port, PHY84328_DEV1_GP_REGISTER_1, reg_data, reg_mask, ucode_csr)); 1164 1165 counters->intf_updates++; 1166 1167 /* Send command */ 1168 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, 1169 reg_data, reg_mask); 1170 if (SOC_FAILURE(rv)) { 1171 LOG_ERROR(BSL_LS_SOC_PHY, 1172 (BSL_META_U(unit, 1173 "84328 failed sending command to ucode: u=%d p=%d err=%d\n"), 1174 unit, port, rv)); 1175 goto fail; 1176 } 1177 1178 /* Handshake with microcode by waiting for ack before moving on */ 1179 checks = 0; 1180 while (checks < 10000) { 1181 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_3, &ucode_csr); 1182 if (SOC_FAILURE(rv)) { 1183 LOG_ERROR(BSL_LS_SOC_PHY, 1184 (BSL_META_U(unit, 1185 "84328 failed reading ucode csr: u=%d p=%d err=%d\n"), 1186 unit, port, rv)); 1187 goto fail; 1188 } 1189 if ((ucode_csr & PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) == 1190 PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) { 1191 break; 1192 } 1193 sal_udelay(100); 1194 checks++; 1195 } 1196 if ((ucode_csr & PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) != 1197 PHY84328_DEV1_GP_REGISTER_3_FINISH_CHANGE_MASK) { 1198 uint16 micro_en; 1199 (void) READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, &drv_csr); 1200 (void) READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, µ_en); 1201 LOG_ERROR(BSL_LS_SOC_PHY, 1202 (BSL_META_U(unit, 1203 "84328: microcode failed to ack: u=%d p=%d 1.%04x=%04x 1.%04x=%04x " 1204 "1.%04x=%04x checks=%d\n"), 1205 unit, port, 1206 PHY84328_DEV1_GP_REGISTER_1, drv_csr, 1207 PHY84328_DEV1_GP_REGISTER_3, ucode_csr, 1208 PHY84328_DEV1_GP_REG_0, micro_en, 1209 checks)); 1210 rv = SOC_E_TIMEOUT; 1211 goto fail; 1212 } 1213 1214 /* Cmd active and ucode acked - let ucode know we saw ack */ 1215 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, 1216 0, PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK); 1217 if (rv != SOC_E_NONE) { 1218 goto fail; 1219 } 1220 1221 fail: 1222 if (saved_side == PHY84328_INTF_SIDE_SYS) { 1223 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 1224 } 1225 1226 return rv; 1227 } 1228 1229 /* 1230 * Populates interface type and speed for line and system side interfaces based on 1231 * line side interface speed and system side interface type 1232 * 1233 * Assumption: 1234 * line_intf->speed: must already be set based on port configuration 1235 * sys_intf->type: must be set to either the configured _spn_PHY_SYS_INTERFACE value or default 1236 */ 1237 STATIC int 1238 _phy_84328_intf_line_sys_params_get(int unit, soc_port_t port) 1239 { 1240 phy84328_intf_cfg_t *line_intf; 1241 phy84328_intf_cfg_t *sys_intf; 1242 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1243 1244 line_intf = &(LINE_INTF(pc)); 1245 sys_intf = &(SYS_INTF(pc)); 1246 1247 /* 1248 * System side interface was specified so make sure it's compatible with 1249 * line side speed. If not, overwrite with default compatible interface 1250 */ 1251 if (PHY84328_MULTI_CORE_MODE(pc)) { 1252 sys_intf->speed = 100000; 1253 line_intf->type = SOC_PORT_IF_CAUI; 1254 sys_intf->type = SOC_PORT_IF_CAUI; 1255 } else if (line_intf->speed == 40000) { 1256 sys_intf->speed = 40000; 1257 line_intf->type = SOC_PORT_IF_SR4; 1258 if (!(_phy_84328_intf_is_single_port(sys_intf->type))) { 1259 /* system side interface is not compatible so overwrite with default */ 1260 LOG_ERROR(BSL_LS_SOC_PHY, 1261 (BSL_META_U(unit, 1262 "PHY84328 incompatible 40G system side interface, " 1263 "using default: u=%d p=%d\n"), unit, port)); 1264 sys_intf->type = SOC_PORT_IF_XLAUI; 1265 } 1266 } else { /* 10G/1G */ 1267 if (_phy_84328_intf_is_quad_port(sys_intf->type)) { 1268 if (sys_intf->type == SOC_PORT_IF_KX) { 1269 line_intf->speed = 1000; 1270 line_intf->type = SOC_PORT_IF_GMII; 1271 sys_intf->speed = 1000; 1272 } else { 1273 /* 10G system side so fix line side to be 10G compatible */ 1274 line_intf->speed = 10000; 1275 line_intf->type = SOC_PORT_IF_SR; 1276 sys_intf->speed = 10000; 1277 } 1278 } else { 1279 /* system side interface is not compatible so overwrite with default */ 1280 LOG_ERROR(BSL_LS_SOC_PHY, 1281 (BSL_META_U(unit, 1282 "PHY84328 incompatible 10G/1G system side interface, " 1283 "using default: u=%d p=%d\n"), unit, port)); 1284 /* default to 10G interface/speed on both sides */ 1285 line_intf->speed = 10000; 1286 line_intf->type = SOC_PORT_IF_SR; 1287 sys_intf->speed = 10000; 1288 sys_intf->type = SOC_PORT_IF_XFI; 1289 } 1290 } 1291 return SOC_E_NONE; 1292 } 1293 1294 STATIC int 1295 _phy_84328_intf_line_sys_update(int unit, soc_port_t port) 1296 { 1297 phy_ctrl_t *pc; 1298 phy_ctrl_t *int_pc; 1299 int int_phy_en = 0; 1300 uint16 data = 0, mask = 0; 1301 uint16 reg_data = 0, reg_mask = 0; 1302 phy84328_intf_cfg_t *line_intf, *sys_intf; 1303 1304 pc = EXT_PHY_SW_STATE(unit, port); 1305 int_pc = INT_PHY_SW_STATE(unit, port); 1306 line_intf = &(LINE_INTF(pc)); 1307 sys_intf = &(SYS_INTF(pc)); 1308 1309 _phy_84328_intf_print(unit, port, "intf update"); 1310 1311 reg_data = 0; 1312 reg_mask = 0; 1313 SOC_IF_ERROR_RETURN( 1314 _phy_84328_intf_type_reg_get(unit, port, line_intf->type, 1315 PHY84328_INTF_SIDE_LINE, &data, &mask)); 1316 reg_data |= data; 1317 reg_mask |= mask; 1318 1319 SOC_IF_ERROR_RETURN( 1320 _phy_84328_intf_type_reg_get(unit, port, sys_intf->type, 1321 PHY84328_INTF_SIDE_SYS, &data, &mask)); 1322 reg_data |= data; 1323 reg_mask |= mask; 1324 1325 SOC_IF_ERROR_RETURN( 1326 _phy_84328_intf_speed_reg_get(unit, port, line_intf->speed, &data, &mask)); 1327 reg_data |= data; 1328 reg_mask |= mask; 1329 1330 SOC_IF_ERROR_RETURN( 1331 _phy_84328_intf_datapath_reg_get(unit, port, CUR_DATAPATH(pc), &data, &mask)); 1332 reg_data |= data; 1333 reg_mask |= mask; 1334 1335 LOG_INFO(BSL_LS_SOC_PHY, 1336 (BSL_META_U(unit, 1337 "84328 intf update: line=%s sys=%s speed=%d (1.%x = %04x/%04x): u=%d p=%d\n"), 1338 phy84328_intf_names[line_intf->type], phy84328_intf_names[sys_intf->type], 1339 line_intf->speed, PHY84328_DEV1_GP_REGISTER_1, reg_data, reg_mask, 1340 unit, port)); 1341 1342 if (SYNC_INIT(pc) == 1) { 1343 SOC_IF_ERROR_RETURN(PHY_ENABLE_GET(int_pc->pd, unit, port, &int_phy_en)); 1344 if (int_phy_en) { 1345 /* Turn off internal PHY while the mode changes */ 1346 SOC_IF_ERROR_RETURN(PHY_ENABLE_SET(int_pc->pd, unit, port, 0)); 1347 } 1348 } 1349 1350 /* GP registers are only on the line side */ 1351 SOC_IF_ERROR_RETURN(_phy_84328_intf_update(unit, port, reg_data, reg_mask)); 1352 1353 if (SYNC_INIT(pc) == 1) { 1354 if (int_phy_en) { 1355 /* If called from PASS2 we skip this and complete in PASS3 */ 1356 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2)) { 1357 INT_PHY_RE_EN(pc) = 1; 1358 /* start timer */ 1359 soc_timeout_init(&SYNC_TO(pc), 10000, 0); 1360 } else { 1361 sal_usleep(10000); 1362 /* Turn internal PHY back on now that the mode has been configured */ 1363 SOC_IF_ERROR_RETURN(PHY_ENABLE_SET(int_pc->pd, unit, port, 1)); 1364 } 1365 } 1366 } 1367 1368 return SOC_E_NONE; 1369 1370 } 1371 1372 /* 1373 * Return the settings in gp_reg_1/gp_register_1 for the inteface speed 1374 * Register data and mask are returned to modify the register. 1375 */ 1376 1377 STATIC int 1378 _phy_84328_intf_speed_reg_get(int unit, soc_port_t port, int speed, uint16 *reg_data, uint16 *reg_mask) 1379 { 1380 *reg_data = 0; 1381 *reg_mask = 0; 1382 switch (speed) { 1383 case 100000: 1384 *reg_data = PHY84328_DEV1_GP_REGISTER_1_SPEED_100G; 1385 break; 1386 case 42000: 1387 *reg_data = PHY84328_DEV1_GP_REGISTER_1_SPEED_42G; 1388 break; 1389 case 40000: 1390 *reg_data = PHY84328_DEV1_GP_REGISTER_1_SPEED_40G; 1391 break; 1392 case 10000: 1393 *reg_data = PHY84328_DEV1_GP_REGISTER_1_SPEED_10G; 1394 break; 1395 case 1000: 1396 case 100: 1397 case 10: 1398 /* This is a special mode that uses the 10G PLL but runs at 1G */ 1399 *reg_data = (PHY84328_DEV1_GP_REGISTER_1_SPEED_10G | 1400 PHY84328_DEV1_GP_REGISTER_1_SPEED_1G); 1401 break; 1402 1403 default : 1404 LOG_ERROR(BSL_LS_SOC_PHY, 1405 (BSL_META_U(unit, 1406 "84328 invalid line speed %d: u=%d p=%d\n"), 1407 speed, unit, port)); 1408 return SOC_E_CONFIG; 1409 } 1410 1411 *reg_data |= PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE; 1412 *reg_mask |= (PHY84328_DEV1_GP_REGISTER_1_SPEED_1G_MASK | 1413 PHY84328_DEV1_GP_REGISTER_1_SPEED_10G_MASK | 1414 PHY84328_DEV1_GP_REGISTER_1_SPEED_40G_MASK | 1415 PHY84328_DEV1_GP_REGISTER_1_SPEED_100G_MASK | 1416 PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK); 1417 1418 LOG_INFO(BSL_LS_SOC_PHY, 1419 (BSL_META_U(unit, 1420 "84328 speed set register: u=%d, p=%d, reg=%04x/%04x), speed=%d\n"), 1421 unit, port, *reg_data, *reg_mask, speed)); 1422 1423 return SOC_E_NONE; 1424 } 1425 1426 STATIC int 1427 _phy_84328_intf_datapath_reg_get(int unit, soc_port_t port, phy84328_datapath_t datapath, 1428 uint16 *reg_data, uint16 *reg_mask) 1429 { 1430 *reg_data = 0; 1431 *reg_mask = 0; 1432 1433 switch (datapath) { 1434 case PHY84328_DATAPATH_20: 1435 *reg_data = 0; 1436 break; 1437 case PHY84328_DATAPATH_4_DEPTH1: 1438 *reg_data = PHY84328_DEV1_GP_REGISTER_1_DATAPATH_4_DEPTH1; 1439 break; 1440 case PHY84328_DATAPATH_4_DEPTH2: 1441 *reg_data = PHY84328_DEV1_GP_REGISTER_1_DATAPATH_4_DEPTH2; 1442 break; 1443 1444 default : 1445 LOG_ERROR(BSL_LS_SOC_PHY, 1446 (BSL_META_U(unit, 1447 "84328 invalid datapath: u=%d p=%d datapath=%d\n"), 1448 unit, port, datapath)); 1449 return SOC_E_CONFIG; 1450 } 1451 *reg_data |= PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE; 1452 *reg_mask = (PHY84328_DEV1_GP_REGISTER_1_DATAPATH_MASK | 1453 PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK); 1454 1455 LOG_INFO(BSL_LS_SOC_PHY, 1456 (BSL_META_U(unit, 1457 "84328 datapath set register: u=%d, p=%d, reg=%04x/%04x, datapath=%d\n"), 1458 unit, port, *reg_data, *reg_mask, datapath)); 1459 1460 return SOC_E_NONE; 1461 } 1462 1463 STATIC int 1464 _phy_84328_intf_datapath_update(int unit, soc_port_t port) 1465 { 1466 phy_ctrl_t *pc; 1467 uint16 data = 0, mask = 0; 1468 1469 pc = EXT_PHY_SW_STATE(unit, port); 1470 1471 SOC_IF_ERROR_RETURN( 1472 _phy_84328_intf_datapath_reg_get(unit, port, CUR_DATAPATH(pc), &data, &mask)); 1473 1474 /* GP registers are only on the line side */ 1475 SOC_IF_ERROR_RETURN(_phy_84328_intf_update(unit, port, data, mask)); 1476 1477 return SOC_E_NONE; 1478 } 1479 1480 /* 1481 * Select channel with mapped access based on interface side and lane number 1482 * For details, see PHY-700 1483 */ 1484 STATIC int 1485 _phy_84328_channel_mapped_select(int unit, soc_port_t port, phy84328_intf_side_t side, int lane) 1486 { 1487 uint16 lane_sel; 1488 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1489 /* logical channel number for physical channel, indexed by lane/channel */ 1490 static uint16 log_ch_map[] = { 0xe4, 0xe1, 0xc6, 0x27 }; 1491 1492 if (lane == PHY84328_ALL_LANES) { 1493 /* Restore 1:1 channel mappings */ 1494 SOC_IF_ERROR_RETURN( 1495 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_LOGAD_CTRL, 0xe4, 0x00ff)); 1496 lane_sel = 1497 (LOGICAL_LANE0(pc) << PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_SHIFT) | 1498 PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK | 1499 PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_BE_DISABLE_IN_SINGLE_PMD_MASK; 1500 } else { 1501 /* System side interface always use first channel which then is mapped */ 1502 if (side == PHY84328_INTF_SIDE_SYS) { 1503 lane_sel = 1; 1504 } else { 1505 /* Select channel in Single PMD 1.ca86[5:4] and [3..0] that corresponds to lane */ 1506 lane_sel = (lane << PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_SHIFT) | 1507 ((1 << lane) & PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_BE_DISABLE_IN_SINGLE_PMD_MASK); 1508 } 1509 } 1510 1511 SOC_IF_ERROR_RETURN( 1512 MODIFY_PHY84328_MMF_PMA_PMD_REG( 1513 unit, pc, PHY84328_DEV1_SINGLE_PMD_CTRL, lane_sel, 1514 PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_MASK | 1515 PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_BE_DISABLE_IN_SINGLE_PMD_MASK)); 1516 1517 if (side == PHY84328_INTF_SIDE_SYS) { 1518 /* Map the logical channel from physical channel */ 1519 lane_sel = (lane == PHY84328_ALL_LANES) ? log_ch_map[0] : log_ch_map[lane]; 1520 SOC_IF_ERROR_RETURN( 1521 MODIFY_PHY84328_MMF_PMA_PMD_REG( 1522 unit, pc, PHY84328_DEV1_LOGAD_CTRL, lane_sel, 0x00ff)); 1523 1524 /* Now go to system side to access register */ 1525 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 1526 } 1527 1528 return SOC_E_NONE; 1529 } 1530 1531 /* 1532 * Directly select channel to access based on interface side and lane number. 1533 */ 1534 STATIC int 1535 _phy_84328_channel_direct_select(int unit, soc_port_t port, phy84328_intf_side_t side, int lane) 1536 { 1537 uint16 lane_sel; 1538 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1539 1540 /* 1541 * If all lanes, restore single PMD access with lane 0 broadcast to all lanes 1542 * For single lane, select lane in Single PMD 1.ca86[5:4] and [3..0] that corresponds 1543 * to the lane with direct lane selection in 1.ca86[8] 1544 */ 1545 if (lane == PHY84328_ALL_LANES) { 1546 lane_sel = 1547 (LOGICAL_LANE0(pc) << PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_SHIFT) | 1548 PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK | 1549 PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_BE_DISABLE_IN_SINGLE_PMD_MASK; 1550 } else { 1551 lane_sel = 0x100 | (lane << PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_SHIFT) | 1552 ((1 << lane) & PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_BE_DISABLE_IN_SINGLE_PMD_MASK); 1553 } 1554 1555 SOC_IF_ERROR_RETURN( 1556 MODIFY_PHY84328_MMF_PMA_PMD_REG( 1557 unit, pc, PHY84328_DEV1_SINGLE_PMD_CTRL, lane_sel, 1558 0x100 | PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_MASK | 1559 PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_BE_DISABLE_IN_SINGLE_PMD_MASK)); 1560 1561 if (side == PHY84328_INTF_SIDE_SYS) { 1562 /* Now go to system side to access register */ 1563 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 1564 } 1565 return SOC_E_NONE; 1566 } 1567 1568 /* 1569 * Select channel to access based on interface side and lane number. 1570 * The side is selected before returning. 1571 */ 1572 STATIC int 1573 _phy_84328_channel_select(int unit, soc_port_t port, phy84328_intf_side_t side, int lane) 1574 { 1575 int rv; 1576 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1577 1578 if (!(PHY84328_SINGLE_PORT_MODE(pc))) { 1579 return SOC_E_PARAM; 1580 } 1581 1582 if (!((lane == PHY84328_ALL_LANES) || ((lane >= 0) && (lane <= 3)))) { 1583 return SOC_E_PARAM; 1584 } 1585 1586 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1587 1588 if ((side == PHY84328_INTF_SIDE_LINE) || (DEVREV(pc) != 0x00a0)) { 1589 rv = _phy_84328_channel_direct_select(unit, port, side, lane); 1590 } else { 1591 rv = _phy_84328_channel_mapped_select(unit, port, side, lane); 1592 } 1593 1594 return rv; 1595 } 1596 1597 /* 1598 * 20-bit: set txpol in line side 1.c061[5] 1599 * 4-bit: set txpol in line side 1.c068[12] 1600 */ 1601 STATIC int 1602 _phy_84328_polarity_flip_tx_set(int unit, soc_port_t port, int flip) 1603 { 1604 uint16 data, mask; 1605 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1606 1607 /* Clear to flip, set to unflip */ 1608 if (CUR_DATAPATH(pc) == PHY84328_DATAPATH_20) { 1609 data = flip ? 0 : PHY84328_DEV1_ANATXACONTROL_TXPOL_FLIP_MASK; 1610 mask = PHY84328_DEV1_ANATXACONTROL_TXPOL_FLIP_MASK; 1611 SOC_IF_ERROR_RETURN( 1612 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL, data, mask)); 1613 } else { 1614 data = flip ? 0 : PHY84328_DEV1_ANATXACONTROL4_XFI_LOWLATENCY_POLARITY_FLIP_MASK; 1615 mask = PHY84328_DEV1_ANATXACONTROL4_XFI_LOWLATENCY_POLARITY_FLIP_MASK; 1616 SOC_IF_ERROR_RETURN( 1617 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL4, data, mask)); 1618 } 1619 return SOC_E_NONE; 1620 } 1621 1622 STATIC int 1623 _phy_84328_polarity_flip_tx(int unit, soc_port_t port, uint16 cfg_pol) 1624 { 1625 int flip; 1626 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1627 1628 if ((PHY84328_SINGLE_PORT_MODE(pc))) { 1629 int lane; 1630 for (lane = 0; lane < PHY84328_NUM_LANES; lane++) { 1631 /* Check for all lanes or whether this lane has polarity flipped */ 1632 if ((cfg_pol == POL_CONFIG_ALL_LANES) || 1633 ((cfg_pol & POL_CONFIG_LANE_MASK(lane)) == POL_CONFIG_LANE_MASK(lane))) { 1634 flip = 1; 1635 } else { 1636 flip = 0; 1637 } 1638 LOG_INFO(BSL_LS_SOC_PHY, 1639 (BSL_META_U(unit, 1640 "84328 tx polarity flip=%d: u=%d p=%d lane=%d\n"), flip, unit, port, lane)); 1641 1642 /* Select the lane on the line side */ 1643 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, lane)); 1644 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_tx_set(unit, port, flip)); 1645 } 1646 /* Restore to default single port register access */ 1647 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, PHY84328_ALL_LANES)); 1648 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1649 } 1650 else { /* quad mode */ 1651 flip = PHY84328_10G_POL_CFG_GET(pc,cfg_pol); 1652 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_tx_set(unit, port, flip)); 1653 LOG_INFO(BSL_LS_SOC_PHY, 1654 (BSL_META_U(unit, 1655 "84328 polarity flip: u=%d p=%d\n"), unit, port)); 1656 } 1657 1658 return SOC_E_NONE; 1659 } 1660 1661 1662 /* RX polarity in 20-bit line side with rx inversion in 1.c0ba[3:2] */ 1663 STATIC int 1664 _phy_84328_polarity_flip_rx_20bit(int unit, soc_port_t port, int flip) 1665 { 1666 uint16 data, mask; 1667 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1668 1669 /* Default is clear, set to flip it */ 1670 data = flip ? (PHY84328_DEV1_GP_REGISTER_RX_INV_FORCE | PHY84328_DEV1_GP_REGISTER_RX_INV_INVERT) : 0; 1671 mask = (PHY84328_DEV1_GP_REGISTER_RX_INV_FORCE | PHY84328_DEV1_GP_REGISTER_RX_INV_INVERT); 1672 1673 SOC_IF_ERROR_RETURN( 1674 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_RX_INV, data, mask)); 1675 1676 return SOC_E_NONE; 1677 } 1678 1679 /* RX polarity in 4-bit system side polarity in 1.c068[12] */ 1680 STATIC int 1681 _phy_84328_polarity_flip_rx_4bit(int unit, soc_port_t port, int flip) 1682 { 1683 uint16 data, mask; 1684 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1685 1686 /* Default is set, clear to flip it */ 1687 data = flip ? 0 : PHY84328_DEV1_ANATXACONTROL4_XFI_LOWLATENCY_POLARITY_FLIP_MASK; 1688 mask = PHY84328_DEV1_ANATXACONTROL4_XFI_LOWLATENCY_POLARITY_FLIP_MASK; 1689 1690 SOC_IF_ERROR_RETURN( 1691 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL4, data, mask)); 1692 1693 return SOC_E_NONE; 1694 } 1695 1696 STATIC int 1697 _phy_84328_polarity_flip_rx(int unit, soc_port_t port, uint16 cfg_pol) 1698 { 1699 int flip; 1700 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1701 1702 /* 1703 * RX polarity flipping in 20-bit done on the line side while 4-bit done on the system side 1704 */ 1705 if ((PHY84328_SINGLE_PORT_MODE(pc))) { 1706 int lane; 1707 1708 /* 4-bit polarity handled on system side */ 1709 if (CUR_DATAPATH(pc) != PHY84328_DATAPATH_20) { 1710 PHY_84328_MICRO_PAUSE(unit, port, "polarity rx"); 1711 } 1712 for (lane = 0; lane < PHY84328_NUM_LANES; lane++) { 1713 flip = 0; 1714 if ((cfg_pol == POL_CONFIG_ALL_LANES) || 1715 ((cfg_pol & POL_CONFIG_LANE_MASK(lane)) == POL_CONFIG_LANE_MASK(lane))) { 1716 flip = 1; 1717 } 1718 if (CUR_DATAPATH(pc) == PHY84328_DATAPATH_20) { 1719 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, lane)); 1720 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_rx_20bit(unit, port, flip)); 1721 } else { 1722 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_SYS, lane)); 1723 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_rx_4bit(unit, port, flip)); 1724 } 1725 LOG_INFO(BSL_LS_SOC_PHY, 1726 (BSL_META_U(unit, 1727 "84328 rx polarity flip: u=%d p=%d lane=%d\n"), unit, port, lane)); 1728 } 1729 /* Restore to default single port register access */ 1730 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, PHY84328_ALL_LANES)); 1731 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1732 if (CUR_DATAPATH(pc) != PHY84328_DATAPATH_20) { 1733 PHY_84328_MICRO_RESUME(unit, port); 1734 } 1735 1736 } 1737 else { /* quad mode */ 1738 1739 flip = PHY84328_10G_POL_CFG_GET(pc,cfg_pol); 1740 if (CUR_DATAPATH(pc) == PHY84328_DATAPATH_20) { 1741 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1742 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_rx_20bit(unit, port, flip)); 1743 } else { 1744 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 1745 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_rx_4bit(unit, port, flip)); 1746 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 1747 } 1748 LOG_INFO(BSL_LS_SOC_PHY, 1749 (BSL_META_U(unit, 1750 "84328 rx polarity flip: u=%d p=%d\n"), unit, port)); 1751 } 1752 1753 1754 return SOC_E_NONE; 1755 } 1756 1757 1758 /* 1759 * Flip configured tx/rx polarities 1760 * 1761 * Property values are either 1 for all lanes or 1762 * lane 0: 000f 1763 * lane 1: 00f0 1764 * lane 2: 0f00 1765 * lane 3: f000 1766 */ 1767 STATIC int 1768 _phy_84328_polarity_flip(int unit, soc_port_t port, uint16 cfg_tx_pol, uint16 cfg_rx_pol) 1769 { 1770 LOG_INFO(BSL_LS_SOC_PHY, 1771 (BSL_META_U(unit, 1772 "84328 polarity flip: u=%d p%d TX=%x RX=%x\n"), unit, port, 1773 cfg_tx_pol, cfg_rx_pol)); 1774 1775 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_tx(unit, port, cfg_tx_pol)); 1776 1777 SOC_IF_ERROR_RETURN(_phy_84328_polarity_flip_rx(unit, port, cfg_rx_pol)); 1778 1779 return SOC_E_NONE; 1780 } 1781 1782 1783 STATIC int 1784 _phy_84328_config_devid(int unit,soc_port_t port, phy_ctrl_t *pc, uint32 *devid) 1785 { 1786 if (soc_property_port_get(unit, port, "phy_84328", FALSE)) { 1787 return *devid = PHY84328_ID_84328; 1788 } 1789 1790 return _phy_84328_chip_id_get(unit, port, pc, devid); 1791 } 1792 1793 STATIC int 1794 _phy_84328_tx_mode_set(int unit, soc_port_t port, phy84328_intf_side_t side, uint16 tx_mode) 1795 { 1796 phy_ctrl_t *pc; 1797 phy84328_intf_side_t saved_side; 1798 1799 /* Make sure tx_mode has acceptable values */ 1800 if ((tx_mode != 0) && (tx_mode != 1) && (tx_mode != 4)) { 1801 LOG_ERROR(BSL_LS_SOC_PHY, 1802 (BSL_META_U(unit, 1803 "PHY84328 invalid tx mode configuration - must be 0, 1, or 4: u%d p%d\n"), 1804 unit, port)); 1805 return SOC_E_NONE; 1806 } 1807 1808 pc = EXT_PHY_SW_STATE(unit, port); 1809 1810 saved_side = _phy_84328_intf_side_regs_get(unit, port); 1811 _phy_84328_intf_side_regs_select(unit, port, side); 1812 1813 /* Set manual tx mode updates */ 1814 SOC_IF_ERROR_RETURN(_phy_84328_txmode_manual_set(unit, port, side, TRUE)); 1815 SOC_IF_ERROR_RETURN( 1816 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL2, 1817 tx_mode << PHY84328_DEV1_ANATXACONTROL2_TX_MODESELECT_SHIFT, 1818 PHY84328_DEV1_ANATXACONTROL2_TX_MODESELECT_MASK)); 1819 if (saved_side != side) { 1820 _phy_84328_intf_side_regs_select(unit, port, saved_side); 1821 } 1822 1823 return SOC_E_NONE; 1824 } 1825 1826 STATIC int 1827 _phy_84328_tx_mode_get(int unit, soc_port_t port, phy84328_intf_side_t side, uint16 *tx_mode) 1828 { 1829 phy_ctrl_t *pc; 1830 uint16 data; 1831 phy84328_intf_side_t saved_side; 1832 1833 pc = EXT_PHY_SW_STATE(unit, port); 1834 1835 saved_side = _phy_84328_intf_side_regs_get(unit, port); 1836 _phy_84328_intf_side_regs_select(unit, port, side); 1837 1838 SOC_IF_ERROR_RETURN( 1839 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL2, 1840 &data)); 1841 1842 /* Must exclude bit 13 from tx_mode */ 1843 *tx_mode = (data >> PHY84328_DEV1_ANATXACONTROL2_TX_MODESELECT_SHIFT) & 0xd; 1844 1845 if (saved_side != side) { 1846 _phy_84328_intf_side_regs_select(unit, port, saved_side); 1847 } 1848 1849 return SOC_E_NONE; 1850 } 1851 1852 STATIC int 1853 _phy_84328_tx_config(int unit, soc_port_t port) 1854 { 1855 int tx_mode = -1; 1856 int tx_idriver = -1; 1857 1858 /* tx_modeselect: 0, 1, or 4 */ 1859 tx_mode = soc_property_port_get(unit, port, "phy_line_tx_mode", -1); 1860 if (tx_mode != -1) { 1861 SOC_IF_ERROR_RETURN(_phy_84328_tx_mode_set(unit, port, PHY84328_INTF_SIDE_LINE, 1862 (uint16) tx_mode)); 1863 } 1864 tx_mode = soc_property_port_get(unit, port, "phy_system_tx_mode", -1); 1865 if (tx_mode != -1) { 1866 SOC_IF_ERROR_RETURN(_phy_84328_tx_mode_set(unit, port, PHY84328_INTF_SIDE_SYS, 1867 (uint16) tx_mode)); 1868 } 1869 1870 /* tx idriver: 0..15 */ 1871 tx_idriver = soc_property_port_get(unit, port, "phy_line_driver_current", -1); 1872 if (tx_idriver != -1) { 1873 SOC_IF_ERROR_RETURN(_phy_84328_control_tx_driver_set(unit, port, SOC_PHY_CONTROL_DRIVER_CURRENT, 1874 PHY84328_INTF_SIDE_LINE, tx_idriver)); 1875 } 1876 1877 tx_idriver = soc_property_port_get(unit, port, "phy_system_driver_current", -1); 1878 if (tx_idriver != -1) { 1879 SOC_IF_ERROR_RETURN(_phy_84328_control_tx_driver_set(unit, port, SOC_PHY_CONTROL_DRIVER_CURRENT, 1880 PHY84328_INTF_SIDE_SYS, tx_idriver)); 1881 } 1882 1883 return SOC_E_NONE; 1884 } 1885 1886 STATIC phy84328_datapath_t 1887 _phy_84328_datapath_get(int unit, soc_port_t port) 1888 { 1889 phy84328_datapath_t dp = PHY84328_DATAPATH_20; 1890 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1891 1892 switch (DEVREV(pc)) { 1893 case 0x00a0: 1894 dp = PHY84328_DATAPATH_20; 1895 break; 1896 case 0x00b0: 1897 default: 1898 dp = PHY84328_DATAPATH_4_DEPTH1; 1899 break; 1900 } 1901 return dp; 1902 } 1903 1904 #if 1 1905 STATIC int 1906 _phy_84328_intf_sys_default(int unit, soc_port_t port) 1907 { 1908 uint16 if_sys_idx = 0; 1909 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1910 1911 if (PHY84328_MULTI_CORE_MODE(pc)) { 1912 if_sys_idx = 0; 1913 } else { 1914 /* Get configured system interface */ 1915 if_sys_idx = soc_property_port_get(unit, port, spn_PHY_SYS_INTERFACE, 0); 1916 if (if_sys_idx >= (sizeof(phy_sys_to_port_if) / sizeof(soc_port_if_t))) { 1917 LOG_ERROR(BSL_LS_SOC_PHY, 1918 (BSL_META_U(unit, 1919 "PHY84328 invalid system side interface: u=%d p=%d intf=%d\n" 1920 "Using default interface\n"), 1921 unit, port, if_sys_idx)); 1922 if_sys_idx = 0; 1923 } 1924 } 1925 return if_sys_idx; 1926 } 1927 1928 STATIC int 1929 _phy_84328_intf_line_speed_default(int unit, soc_port_t port) 1930 { 1931 int speed; 1932 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1933 1934 if (PHY84328_MULTI_CORE_MODE(pc)) { 1935 speed = 100000; 1936 } else if (PHY84328_SINGLE_PORT_MODE(pc)) { 1937 speed = 40000; 1938 } else { 1939 speed = 10000; 1940 } 1941 return speed; 1942 } 1943 1944 STATIC soc_port_if_t 1945 _phy_84328_intf_type_default(int speed, phy84328_intf_side_t side) 1946 { 1947 soc_port_if_t intf; 1948 1949 switch (speed) { 1950 case 100000: 1951 /**** SR10 on line side? */ 1952 intf = (side == PHY84328_INTF_SIDE_LINE) ? SOC_PORT_IF_SR4 : SOC_PORT_IF_CAUI; 1953 break; 1954 case 40000: 1955 intf = (side == PHY84328_INTF_SIDE_LINE) ? SOC_PORT_IF_SR4 : SOC_PORT_IF_XLAUI; 1956 break; 1957 case 10000: 1958 default: 1959 intf = (side == PHY84328_INTF_SIDE_LINE) ? SOC_PORT_IF_SR : SOC_PORT_IF_XFI; 1960 break; 1961 } 1962 return intf; 1963 } 1964 1965 1966 1967 STATIC int 1968 _phy_84328_intf_default(int unit, soc_port_t port) 1969 { 1970 phy84328_intf_cfg_t *line_intf, *sys_intf; 1971 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 1972 1973 line_intf = &(LINE_INTF(pc)); 1974 sys_intf = &(SYS_INTF(pc)); 1975 sal_memset(line_intf, 0, sizeof(phy84328_intf_cfg_t)); 1976 sal_memset(sys_intf, 0, sizeof(phy84328_intf_cfg_t)); 1977 1978 /* 1979 * - interfaces are KR4/KR/KX/XAUI/XFI/SR/LR/CR/SR4/LR4/CR4/SR10/CR10 1980 * - Gallardo is capable of being configured symmetrically and can support all 1981 * interfaces on both sides 1982 * - system side interfaces cannot be changed dynamically 1983 * - configured in Gallardo via config variables 1984 * - line side mode can be changed dynamically 1985 * - configured specifically with interface set and/or by matching speed 1986 * - automatically when module autodetect is enabled 1987 * 1988 * port mode system side line side 1989 * ---------------- ------------------------ -------------------------------- 1990 * 100G(multicore) dflt:CAUI dflt:SR10 or user set if/speed 1991 * 40G(singleport) dflt:XLAUI or configvar dflt:XLAUI or user set if/speed 1992 * 1G/10G(quadport) dflt:XFI or configvar dflt:SFI or user set if/speed 1993 */ 1994 1995 /* Get configured system interface */ 1996 sys_intf->type = phy_sys_to_port_if[_phy_84328_intf_sys_default(unit, port)]; 1997 line_intf->speed = _phy_84328_intf_line_speed_default(unit, port); 1998 if (sys_intf->type == 0) { 1999 /* use defaults based on current line side */ 2000 sys_intf->speed = line_intf->speed; 2001 line_intf->type = _phy_84328_intf_type_default(line_intf->speed, PHY84328_INTF_SIDE_LINE); 2002 sys_intf->type = _phy_84328_intf_type_default(line_intf->speed, PHY84328_INTF_SIDE_SYS); 2003 _phy_84328_intf_print(unit, port, "default sys intf"); 2004 } else { 2005 SOC_IF_ERROR_RETURN(_phy_84328_intf_line_sys_params_get(unit, port)); 2006 _phy_84328_intf_print(unit, port, "after updating intf based on sys config"); 2007 } 2008 CFG_SYS_INTF(pc) = sys_intf->type; 2009 2010 return SOC_E_NONE; 2011 } 2012 2013 2014 STATIC int 2015 _phy_84328_polarity_cfg_init(int unit, soc_port_t port) 2016 { 2017 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 2018 2019 /* 2020 * The core aware property which specifies the core number must be 2021 * with multiple core ports 2022 * 2023 * Ex: 2024 * Assuming port 4 is a 100G port, then if every other lane has tx 2025 * polarity flipped: 2026 * config add phy_tx_polarity_flip_core0_port4=0x0f0f 2027 * config add phy_tx_polarity_flip_core1_port4=0x0f0f 2028 * config add phy_tx_polarity_flip_core2_port4=0x000f 2029 * 2030 * Polarity configuration: 2031 * 1: all lanes 2032 * nibble==0xF: each nibble specifies a lane - up to 4 lanes 2033 * 2034 * The polarity configuration is stored in the driver per core control block 2035 */ 2036 if (PHY84328_MULTI_CORE_MODE(pc)) { 2037 POL_TX_CFG(pc) = soc_property_port_suffix_num_get(unit, port, CORE_NUM(pc), 2038 spn_PHY_TX_POLARITY_FLIP, 2039 "core", 0); 2040 POL_RX_CFG(pc) = soc_property_port_suffix_num_get(unit, port, CORE_NUM(pc), 2041 spn_PHY_RX_POLARITY_FLIP, 2042 "core", 0); 2043 } else { 2044 POL_TX_CFG(pc) = soc_property_port_get(unit, port, spn_PHY_TX_POLARITY_FLIP, 0); 2045 POL_RX_CFG(pc) = soc_property_port_get(unit, port, spn_PHY_RX_POLARITY_FLIP, 0); 2046 } 2047 2048 return SOC_E_NONE; 2049 } 2050 2051 2052 #endif /* 100G */ 2053 2054 #ifdef BCM_WARM_BOOT_SUPPORT 2055 STATIC int 2056 _phy_84328_intf_speed_from_reg(uint16 mode, int *speed) 2057 { 2058 uint16 speed_reg = mode & (PHY84328_DEV1_GP_REGISTER_1_SPEED_1G_MASK | 2059 PHY84328_DEV1_GP_REGISTER_1_SPEED_10G_MASK | 2060 PHY84328_DEV1_GP_REGISTER_1_SPEED_40G_MASK | 2061 PHY84328_DEV1_GP_REGISTER_1_SPEED_100G_MASK); 2062 *speed = 0; 2063 switch (speed_reg) { 2064 2065 case PHY84328_DEV1_GP_REGISTER_1_SPEED_100G: 2066 *speed = 100000; 2067 break; 2068 2069 case PHY84328_DEV1_GP_REGISTER_1_SPEED_42G: 2070 *speed = 42000; 2071 break; 2072 2073 case PHY84328_DEV1_GP_REGISTER_1_SPEED_40G: 2074 *speed = 40000; 2075 break; 2076 2077 case PHY84328_DEV1_GP_REGISTER_1_SPEED_10G: 2078 *speed = 10000; 2079 break; 2080 2081 case PHY84328_DEV1_GP_REGISTER_1_SPEED_10G | PHY84328_DEV1_GP_REGISTER_1_SPEED_1G: 2082 /********* 100, 10 not recoverable from PHY ********/ 2083 *speed = 1000; 2084 break; 2085 default: 2086 /* hardware has unexpected value */ 2087 return SOC_E_FAIL; 2088 } 2089 return SOC_E_NONE; 2090 } 2091 2092 STATIC int 2093 _phy_84328_intf_type_from_reg(uint16 mode, phy84328_intf_side_t side, int speed, int an, 2094 soc_port_if_t *intf_type) 2095 { 2096 uint16 intf_reg = mode & ((side == PHY84328_INTF_SIDE_LINE) ? 0x5300 : 0xac00); 2097 2098 if (side == PHY84328_INTF_SIDE_LINE) { 2099 switch (intf_reg) { 2100 case 0: 2101 switch (speed) { 2102 case 40000: 2103 case 42000: 2104 case 100000: 2105 *intf_type = SOC_PORT_IF_SR4; 2106 break; 2107 case 10000: 2108 *intf_type = SOC_PORT_IF_SR; 2109 break; 2110 case 1000: 2111 if (an) { 2112 *intf_type = SOC_PORT_IF_GMII; 2113 } else { 2114 *intf_type = SOC_PORT_IF_SGMII; 2115 } 2116 break; 2117 case 100: 2118 case 10: 2119 *intf_type = SOC_PORT_IF_SGMII; 2120 break; 2121 default: 2122 return SOC_E_FAIL; 2123 } 2124 2125 break; 2126 2127 case 0x4200: 2128 switch (speed) { 2129 case 100000: 2130 *intf_type = SOC_PORT_IF_CAUI; 2131 break; 2132 case 40000: 2133 case 42000: 2134 *intf_type = SOC_PORT_IF_XLAUI; 2135 break; 2136 case 10000: 2137 *intf_type = SOC_PORT_IF_SFI; 2138 break; 2139 default: 2140 return SOC_E_FAIL; 2141 } 2142 break; 2143 2144 case 0x4000: 2145 switch (speed) { 2146 case 40000: 2147 case 42000: 2148 *intf_type = SOC_PORT_IF_LR4; 2149 break; 2150 case 10000: 2151 *intf_type = SOC_PORT_IF_LR; 2152 break; 2153 default: 2154 return SOC_E_FAIL; 2155 } 2156 break; 2157 2158 case 0x200: 2159 switch (speed) { 2160 case 40000: 2161 case 42000: 2162 case 100000: 2163 *intf_type = SOC_PORT_IF_CR4; 2164 break; 2165 case 10000: 2166 *intf_type = SOC_PORT_IF_CR; 2167 break; 2168 default: 2169 return SOC_E_FAIL; 2170 } 2171 break; 2172 2173 case 0x100: 2174 switch (speed) { 2175 case 40000: 2176 case 42000: 2177 *intf_type = SOC_PORT_IF_KR4; 2178 break; 2179 case 10000: 2180 *intf_type = SOC_PORT_IF_KR; 2181 break; 2182 case 1000: 2183 case 100: 2184 case 10: 2185 *intf_type = SOC_PORT_IF_KX; 2186 break; 2187 default: 2188 return SOC_E_FAIL; 2189 } 2190 break; 2191 2192 case 0x1200: 2193 switch (speed) { 2194 case 40000: 2195 case 42000: 2196 case 100000: 2197 *intf_type = SOC_PORT_IF_CR4; 2198 break; 2199 case 10000: 2200 *intf_type = SOC_PORT_IF_CR; 2201 break; 2202 default: 2203 return SOC_E_FAIL; 2204 } 2205 break; 2206 2207 case 0x5000: 2208 switch (speed) { 2209 case 10000: 2210 *intf_type = SOC_PORT_IF_ZR; 2211 break; 2212 default: 2213 return SOC_E_FAIL; 2214 } 2215 break; 2216 2217 case 0x1000: 2218 default: 2219 return SOC_E_FAIL; 2220 break; 2221 } /* switch (intf_reg) */ 2222 } else { 2223 /* get sys intf type */ 2224 switch (intf_reg) { 2225 case 0: 2226 switch (speed) { 2227 case 40000: 2228 case 42000: 2229 *intf_type = SOC_PORT_IF_SR4; 2230 break; 2231 case 10000: 2232 *intf_type = SOC_PORT_IF_SR; 2233 break; 2234 case 1000: 2235 if (an) { 2236 *intf_type = SOC_PORT_IF_GMII; 2237 } else { 2238 *intf_type = SOC_PORT_IF_SGMII; 2239 } 2240 break; 2241 case 100: 2242 case 10: 2243 *intf_type = SOC_PORT_IF_SGMII; 2244 break; 2245 default: 2246 return SOC_E_FAIL; 2247 } 2248 2249 break; 2250 2251 case 0x8800: 2252 switch (speed) { 2253 case 100000: 2254 *intf_type = SOC_PORT_IF_CAUI; 2255 break; 2256 case 40000: 2257 case 42000: 2258 *intf_type = SOC_PORT_IF_XLAUI; 2259 break; 2260 case 10000: 2261 *intf_type = SOC_PORT_IF_XFI; 2262 break; 2263 default: 2264 return SOC_E_FAIL; 2265 } 2266 break; 2267 2268 case 0x800: 2269 switch (speed) { 2270 case 40000: 2271 case 42000: 2272 case 100000: 2273 *intf_type = SOC_PORT_IF_CR4; 2274 break; 2275 case 10000: 2276 *intf_type = SOC_PORT_IF_CR; 2277 break; 2278 default: 2279 return SOC_E_FAIL; 2280 } 2281 break; 2282 2283 case 0x400: 2284 switch (speed) { 2285 case 40000: 2286 case 42000: 2287 *intf_type = SOC_PORT_IF_KR4; 2288 break; 2289 case 10000: 2290 *intf_type = SOC_PORT_IF_KR; 2291 break; 2292 case 1000: 2293 case 100: 2294 case 10: 2295 *intf_type = SOC_PORT_IF_KX; 2296 break; 2297 default: 2298 return SOC_E_FAIL; 2299 } 2300 break; 2301 2302 case 0x2800: 2303 switch (speed) { 2304 case 40000: 2305 case 42000: 2306 case 100000: 2307 *intf_type = SOC_PORT_IF_CR4; 2308 break; 2309 case 10000: 2310 *intf_type = SOC_PORT_IF_CR; 2311 break; 2312 default: 2313 return SOC_E_FAIL; 2314 } 2315 break; 2316 2317 case 0xa000: 2318 case 0x2000: 2319 default: 2320 return SOC_E_FAIL; 2321 break; 2322 } /* switch (intf_reg) */ 2323 2324 } 2325 return SOC_E_NONE; 2326 } 2327 2328 2329 STATIC int 2330 _phy_84328_reinit_line_intf(int unit, soc_port_t port, int speed, int an, uint16 mode) 2331 { 2332 phy_ctrl_t *pc; 2333 phy84328_intf_cfg_t *line_intf; 2334 2335 pc = EXT_PHY_SW_STATE(unit, port); 2336 line_intf = &(LINE_INTF(pc)); 2337 2338 line_intf->speed = speed; 2339 SOC_IF_ERROR_RETURN(_phy_84328_intf_type_from_reg(mode, PHY84328_INTF_SIDE_LINE, speed, an, &(line_intf->type))); 2340 2341 if (AN_EN(pc) && line_intf->type == SOC_PORT_IF_CR4) { 2342 if (POL_RX_CFG(pc)) { 2343 FORCE_20BIT(pc) |= FORCE_20BIT_AN ; 2344 } 2345 } 2346 2347 return SOC_E_NONE; 2348 } 2349 2350 STATIC int 2351 _phy_84328_reinit_system_intf(int unit, soc_port_t port, int speed, int an, uint16 mode) 2352 { 2353 phy_ctrl_t *pc; 2354 phy84328_intf_cfg_t *system_intf; 2355 2356 pc = EXT_PHY_SW_STATE(unit, port); 2357 system_intf = &(SYS_INTF(pc)); 2358 2359 system_intf->speed = speed; 2360 SOC_IF_ERROR_RETURN(_phy_84328_intf_type_from_reg(mode, PHY84328_INTF_SIDE_SYS, speed, an, &(system_intf->type))); 2361 2362 return SOC_E_NONE; 2363 } 2364 2365 /* 2366 * For WarmBoot support: preserve SW RxLOS enable/disable status in register 1.0xC01A 2367 */ 2368 #define PHY84328_NO_PRESERVE_SW_RxLOS 0x100 2369 #define PHY84328_DEV1_LANECTRL_RSV_SHIFT 12 2370 STATIC int 2371 _phy_84328_preserve_sw_rx_los(int unit, soc_port_t port, int enable) 2372 { 2373 uint32 offset; 2374 uint16 sw_rx_los_enable; 2375 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 2376 2377 /* get the offset of this port/lane */ 2378 SOC_IF_ERROR_RETURN( 2379 phy_84328_control_port_get(unit, port, SOC_PHY_CONTROL_PORT_OFFSET, &offset) ); 2380 offset = 1U << (offset + PHY84328_DEV1_LANECTRL_RSV_SHIFT); 2381 sw_rx_los_enable = (enable) ? offset : 0 ; 2382 2383 /* register 1.0xC01A , use the reserved bits [15:12] *\ 2384 \* to preserve SW RxLOS status for warmboot support */ 2385 return MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 2386 PHY84328_DEV1_LANECTRL, sw_rx_los_enable, (uint16) offset); 2387 } 2388 2389 STATIC int _phy_84328_sw_rx_los_control_set(int unit, soc_port_t port, uint32 value); 2390 /* 2391 * During WarmBoot: retrieve SW RxLOS enable/disable status from register 1.0xC01A 2392 */ 2393 STATIC int 2394 _phy_84328_reinit_sw_rx_los(int unit, soc_port_t port) 2395 { 2396 uint32 offset; 2397 uint16 sw_rx_los_enable; 2398 phy84328_sw_rx_los_t *sw_rx_los; 2399 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 2400 sw_rx_los = &(SW_RX_LOS(pc)); 2401 2402 /* get the offset of this port/lane */ 2403 SOC_IF_ERROR_RETURN( 2404 phy_84328_control_port_get(unit, port, SOC_PHY_CONTROL_PORT_OFFSET, &offset) ); 2405 offset = 1U << (offset + PHY84328_DEV1_LANECTRL_RSV_SHIFT); 2406 2407 /* register 1.0xC01A , use the reserved bits [15:12] *\ 2408 \* to preserve SW RxLOS status during warmboot */ 2409 SOC_IF_ERROR_RETURN( 2410 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 2411 PHY84328_DEV1_LANECTRL, &sw_rx_los_enable) ); 2412 sw_rx_los->cfg_enable = (sw_rx_los_enable & offset) ? TRUE : FALSE; 2413 2414 /* if SW RxLOS was enabled, hardcode the default RxLOS stable state */ 2415 if ( sw_rx_los->cfg_enable ) { 2416 sw_rx_los->cur_enable = 1; 2417 sw_rx_los->sys_link = 1; 2418 sw_rx_los->link_no_pcs = 0; 2419 sw_rx_los->link_status = 0; 2420 sw_rx_los->fault_report_dis = 0; 2421 sw_rx_los->link_no_pcs = 0; 2422 sw_rx_los->restarts = 1; 2423 sw_rx_los->state = PHY84328_SW_RX_LOS_IDLE; 2424 } 2425 2426 return SOC_E_NONE; 2427 } 2428 2429 STATIC int 2430 _phy_84328_reinit_fw_rx_los(int unit, soc_port_t port) 2431 { 2432 uint16 fw_rx_los, fw_rx_los_en_mask; 2433 phy_ctrl_t *pc; 2434 2435 pc = EXT_PHY_SW_STATE(unit, port); 2436 fw_rx_los_en_mask = (1 << 15) | (1 << 14); 2437 2438 SOC_IF_ERROR_RETURN( 2439 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 0xc480, &fw_rx_los)); 2440 2441 FW_RX_LOS(pc) = (fw_rx_los & fw_rx_los_en_mask) == fw_rx_los_en_mask; 2442 2443 return SOC_E_NONE; 2444 } 2445 2446 STATIC int 2447 _phy_84328_reinit_cur_datapath(int unit, soc_port_t port, uint16 mode) 2448 { 2449 uint16 datapath_reg; 2450 phy_ctrl_t *pc; 2451 2452 pc = EXT_PHY_SW_STATE(unit, port); 2453 2454 datapath_reg = mode & PHY84328_DEV1_GP_REGISTER_1_DATAPATH_MASK; 2455 switch (datapath_reg) { 2456 case 0: 2457 CUR_DATAPATH(pc) = PHY84328_DATAPATH_20; 2458 break; 2459 case PHY84328_DEV1_GP_REGISTER_1_DATAPATH_4_DEPTH1: 2460 CUR_DATAPATH(pc) = PHY84328_DATAPATH_4_DEPTH1; 2461 break; 2462 case PHY84328_DEV1_GP_REGISTER_1_DATAPATH_4_DEPTH2: 2463 CUR_DATAPATH(pc) = PHY84328_DATAPATH_4_DEPTH2; 2464 break; 2465 default: 2466 return SOC_E_FAIL; 2467 } 2468 return SOC_E_NONE; 2469 } 2470 2471 2472 STATIC int 2473 _phy_84328_reinit_from_mode(int unit, soc_port_t port) 2474 { 2475 uint16 mode_reg; 2476 uint16 side_reg; 2477 uint16 an_reg; 2478 int speed; 2479 int an =0, an_done = 0; 2480 int int_phy_link = 0; 2481 phy_ctrl_t *pc, *int_pc; 2482 2483 pc = EXT_PHY_SW_STATE(unit, port); 2484 int_pc = INT_PHY_SW_STATE(unit, port); 2485 2486 /* 2487 * Make sure line side registers are selected 2488 * if not, have to bail out since the system is in a bad state 2489 */ 2490 SOC_IF_ERROR_RETURN( 2491 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_XPMD_REGS_SEL, &side_reg)); 2492 if (side_reg != 0) { 2493 return SOC_E_UNAVAIL; 2494 } 2495 2496 /* Read the current mode */ 2497 SOC_IF_ERROR_RETURN( 2498 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, &mode_reg)); 2499 2500 /* Get speed */ 2501 SOC_IF_ERROR_RETURN(_phy_84328_intf_speed_from_reg(mode_reg, &speed)); 2502 2503 /* Get an setting */ 2504 if (speed < 10000) { 2505 if (int_pc != NULL) { 2506 SOC_IF_ERROR_RETURN(PHY_AUTO_NEGOTIATE_GET(int_pc->pd, unit, port, &an, &an_done)); 2507 SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, &speed)); 2508 } 2509 } else { 2510 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_AN_REG(unit, pc, 2511 PHY84328_DEV7_AN_CONTROL_REGISTER, &an_reg)); 2512 an = (an_reg & PHY84328_DEV7_AN_CONTROL_REGISTER_AUTO_NEGOTIATIONENABLE_MASK) == 2513 PHY84328_DEV7_AN_CONTROL_REGISTER_AUTO_NEGOTIATIONENABLE_MASK; 2514 } 2515 2516 AN_EN(pc) = an; 2517 2518 SOC_IF_ERROR_RETURN( 2519 _phy_84328_reinit_line_intf(unit, port, speed, an, mode_reg)); 2520 2521 SOC_IF_ERROR_RETURN( 2522 _phy_84328_reinit_system_intf(unit, port, speed, an, mode_reg)); 2523 2524 SOC_IF_ERROR_RETURN( 2525 _phy_84328_reinit_cur_datapath(unit, port, mode_reg)); 2526 2527 /* 2528 * PCS from the internal PHY is used to determine link. 2529 */ 2530 if (int_pc != NULL) { 2531 SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, &int_phy_link)); 2532 CUR_LINK(pc) = int_phy_link; 2533 } else { 2534 CUR_LINK(pc) = 0; 2535 } 2536 2537 return SOC_E_NONE; 2538 } 2539 2540 STATIC int 2541 _phy_84328_reinit(int unit, soc_port_t port) 2542 { 2543 SOC_IF_ERROR_RETURN( 2544 _phy_84328_reinit_from_mode(unit,port)); 2545 2546 /* Reinit Firmware RxLOS */ 2547 SOC_IF_ERROR_RETURN( 2548 _phy_84328_reinit_fw_rx_los(unit, port)); 2549 /* Reinit Software RxLOS */ 2550 SOC_IF_ERROR_RETURN( 2551 _phy_84328_reinit_sw_rx_los(unit, port) ); 2552 2553 return SOC_E_NONE; 2554 } 2555 #endif /* BCM_WARM_BOOT_SUPPORT */ 2556 2557 STATIC int 2558 _phy_84328_init_pass2(int unit, soc_port_t port) 2559 { 2560 phy_ctrl_t *pc; 2561 phy84328_intf_cfg_t *line_intf, *sys_intf; 2562 phy84328_counters_t *counters; 2563 phy84328_sw_rx_los_t *sw_rx_los; 2564 phy84328_link_mon_t *link_mon; 2565 phy84328_micro_ctrl_t *micro_ctrl; 2566 uint16 data, mask; 2567 uint16 chip_rev; 2568 int tx_gpio0 = 0; 2569 int link_mon_dflt, port_enable_delay_dflt; 2570 2571 LOG_INFO(BSL_LS_SOC_PHY, 2572 (BSL_META_U(unit, 2573 "PHY84328 init pass2: u=%d p=%d\n"), unit, port)); 2574 pc = EXT_PHY_SW_STATE(unit, port); 2575 2576 /* 2577 * - interfaces are KR4/KR/KX/XAUI/XFI/SR/LR/CR/SR4/LR4/CR4 2578 * - Gallardo is capable of being configured symmetrically and can support all 2579 * interfaces on both sides 2580 * - system side interfaces cannot be changed dynamically 2581 * - configured in Gallardo via config variables 2582 * - line side mode can be changed dynamically 2583 * - configured specifically with interface set and/or by matching speed 2584 * - automatically when module autodetect is enabled 2585 * 2586 * port mode system side line side 2587 * ---------------- ------------------------ -------------------------------- 2588 * 40G(singleport) dflt:XLAUI or configvar dflt:XLAUI or user set if/speed 2589 * 1G/10G(quadport) dflt:XFI or configvar dflt:SFI or user set if/speed 2590 */ 2591 2592 line_intf = &(LINE_INTF(pc)); 2593 sys_intf = &(SYS_INTF(pc)); 2594 counters = &(COUNTERS(pc)); 2595 sw_rx_los = &(SW_RX_LOS(pc)); 2596 link_mon = &(LINK_MON(pc)); 2597 micro_ctrl = &(MICRO_CTRL(pc)); 2598 2599 sal_memset(line_intf, 0, sizeof(phy84328_intf_cfg_t)); 2600 sal_memset(sys_intf, 0, sizeof(phy84328_intf_cfg_t)); 2601 sal_memset(counters, 0, sizeof(phy84328_counters_t)); 2602 sal_memset(sw_rx_los, 0, sizeof(phy84328_sw_rx_los_t)); 2603 sal_memset(link_mon, 0, sizeof(phy84328_link_mon_t)); 2604 LOGICAL_LANE0(pc) = 0; 2605 AN_EN(pc) = 0; 2606 FORCE_20BIT(pc) = 0; 2607 CUR_LINK(pc) = 0; 2608 SYNC_INIT(pc) = 1; 2609 INT_PHY_RE_EN(pc) = 0; 2610 DBG_FLAGS(pc) = 0; 2611 FW_RX_LOS(pc) = 0; 2612 BYPASS_SS_TUNING(pc) = soc_property_port_get(unit, port, "phy_84328_bypass_ss_tuning", 1); 2613 SYS_FORCED_CL72(pc) = soc_property_port_get(unit, port, spn_PORT_INIT_CL72, 0); 2614 micro_ctrl->enable = 1; 2615 micro_ctrl->count = 0; 2616 2617 SOC_IF_ERROR_RETURN( 2618 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 2619 PHY84328_DEV1_CHIP_REV_REGISTER, 2620 &chip_rev)); 2621 DEVREV(pc) = chip_rev; 2622 port_enable_delay_dflt = (DEVREV(pc) == 0x00a0) ? 60 : 0; 2623 PORT_ENABLE_DELAY(pc) = soc_property_port_get(unit, port, 2624 "phy_84328_port_enable_delay", 2625 port_enable_delay_dflt) * 1000; 2626 link_mon_dflt = (DEVREV(pc) == 0x00a0) ? 1 : 0; 2627 link_mon->cfg_enable = soc_property_port_get(unit, port, 2628 "phy_84328_link_monitor", 2629 link_mon_dflt); 2630 link_mon->cur_enable = link_mon->cfg_enable; 2631 2632 pc->flags |= PHYCTRL_INIT_DONE; 2633 2634 2635 SOC_IF_ERROR_RETURN(_phy_84328_intf_default(unit, port)); 2636 2637 /* Manually power channel down by default from driver - 2638 * it is upto the user to enable the port through CLI or API or 2639 * by using correct compilation flags to ensure that port is enabled 2640 * as part of initialization by upper layers. 2641 */ 2642 data = (1 << PHY84328_DEV1_OPTICAL_CONFIGURATION_MAN_TXON_EN_SHIFT) | 2643 (1 << PHY84328_DEV1_OPTICAL_CONFIGURATION_TXOFFT_SHIFT); 2644 mask = PHY84328_DEV1_OPTICAL_CONFIGURATION_MAN_TXON_EN_MASK | 2645 PHY84328_DEV1_OPTICAL_CONFIGURATION_TXOFFT_MASK; 2646 2647 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_OPTICAL_CONFIGURATION, 2648 data, mask)); 2649 /* 2650 * Initialize main firmware control register 2651 * - First quiesce firmware and clear default settings 2652 * - Enable all channels as there are race conditions if not all channels are 2653 * enabled when changing to quad-channel mode 2654 * - If tx_gpio0 is set, firmware drives line side tx enable/disable based on 2655 * the system side cdr state 2656 */ 2657 data = PHY84328_DEV1_GP_REG_0_ENABLE_LINE_3_0_MASK | 2658 PHY84328_DEV1_GP_REG_0_ENABLE_SYSTEM_3_0_MASK; 2659 mask = PHY84328_DEV1_GP_REG_0_ENABLE_LINE_3_0_MASK | 2660 PHY84328_DEV1_GP_REG_0_ENABLE_SYSTEM_3_0_MASK; 2661 tx_gpio0 = soc_property_port_get(unit, port, "phy_84328_tx_gpio0", 0); 2662 if (tx_gpio0 == 1) { 2663 data |= PHY84328_DEV1_GP_REG_0_TX_GPIO; 2664 mask |= data; 2665 } 2666 /* Update the core info in bit 6 and 5 */ 2667 mask |= 0x3 << 5; 2668 if (CORE_NUM(pc)){ 2669 data |= ((CORE_NUM(pc) % 3) + 1) << 5 ; 2670 } 2671 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, 2672 data, mask)); 2673 2674 /* Reset does not clear lane control2 */ 2675 SOC_IF_ERROR_RETURN 2676 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_LANECTRL2, 0, 2677 PHY84328_DEV1_LANECTRL2_RLOOP1G_MASK)); 2678 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 2679 SOC_IF_ERROR_RETURN 2680 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_LANECTRL2, 0, 2681 PHY84328_DEV1_LANECTRL2_RLOOP1G_MASK)); 2682 2683 /* Make sure accessing line side registers and 1:1 logical channel mappings */ 2684 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 2685 SOC_IF_ERROR_RETURN( 2686 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_LOGAD_CTRL, 0xe4, 0x00ff)); 2687 2688 CFG_DATAPATH(pc) = _phy_84328_datapath_get(unit, port); 2689 CUR_DATAPATH(pc) = CFG_DATAPATH(pc); 2690 2691 /* Polarity configuration is applied every time interface is configured */ 2692 SOC_IF_ERROR_RETURN(_phy_84328_polarity_cfg_init(unit, port)); 2693 2694 2695 /* Push configuration to the device */ 2696 SOC_IF_ERROR_RETURN(_phy_84328_config_update(unit, port)); 2697 2698 #ifdef BCM_WARM_BOOT_SUPPORT 2699 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)){ 2700 /* Do nothing */ 2701 } else 2702 #endif 2703 { 2704 /* Initialize system and line side interfaces */ 2705 SOC_IF_ERROR_RETURN(_phy_84328_intf_line_sys_init(unit, port)); 2706 } 2707 2708 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) { 2709 /* indicate third pass of init is needed */ 2710 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS3); 2711 } 2712 2713 return SOC_E_NONE; 2714 } 2715 2716 STATIC int 2717 _phy_84328_init_pass3(int unit, soc_port_t port) 2718 { 2719 int rv; 2720 phy_ctrl_t *pc, *int_pc; 2721 int regulator_en = 0; 2722 2723 LOG_INFO(BSL_LS_SOC_PHY, 2724 (BSL_META_U(unit, 2725 "PHY84328 init pass3: u=%d p=%d\n"), unit, port)); 2726 pc = EXT_PHY_SW_STATE(unit, port); 2727 int_pc = INT_PHY_SW_STATE(unit, port); 2728 2729 /* Complete what we started from PASS2 in PASS3 */ 2730 if (INT_PHY_RE_EN(pc)) { 2731 /* wait for timer to expire */ 2732 while (!soc_timeout_check(&SYNC_TO(pc))) { 2733 sal_usleep(100); 2734 } 2735 2736 /* Turn internal PHY back on now that the mode has been configured */ 2737 SOC_IF_ERROR_RETURN(PHY_ENABLE_SET(int_pc->pd, unit, port, 1)); 2738 INT_PHY_RE_EN(pc) = 0; 2739 } 2740 2741 2742 LOG_INFO(BSL_LS_SOC_PHY, 2743 (BSL_META_U(unit, 2744 "PHY84328 init pass3 polarity verified: u=%d p=%d\n"), unit, port)); 2745 2746 regulator_en = soc_property_port_get(unit, port, spn_PHY_AUX_VOLTAGE_ENABLE, 0); 2747 if (regulator_en) { 2748 /* Clear 1.c850[13] to enable */ 2749 SOC_IF_ERROR_RETURN 2750 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_REGUALTOR_CTRL, 0, 2751 PHY84328_DEV1_REGUALTOR_CTRL_PWRDN_MASK)); 2752 } 2753 2754 /* Logical lane0 used for auto-negotiation in 40G CR4 */ 2755 if (PHY84328_SINGLE_PORT_MODE(pc)) { 2756 uint16 logical_lane0; 2757 2758 logical_lane0 = soc_property_port_get(unit, port, spn_PHY_LANE0_L2P_MAP, 0); 2759 if (logical_lane0 > PHY84328_NUM_LANES) { 2760 LOG_ERROR(BSL_LS_SOC_PHY, 2761 (BSL_META_U(unit, 2762 "PHY84328 bad auto-negotiation lane %d: u=%d p=%d" 2763 " lane must be 0..3\n"), (int)logical_lane0, unit, port)); 2764 } else { 2765 SOC_IF_ERROR_RETURN( 2766 MODIFY_PHY84328_MMF_PMA_PMD_REG( 2767 unit, pc, PHY84328_DEV1_SINGLE_PMD_CTRL, 2768 logical_lane0 << PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_SHIFT, 2769 PHY84328_DEV1_SINGLE_PMD_CTRL_PHY_CH_TO_ACCESS_IN_SINGLE_PMD_MASK)); 2770 LOGICAL_LANE0(pc) = logical_lane0; 2771 } 2772 } 2773 2774 /* If configured, enable module auto detection */ 2775 MOD_AUTO_DETECT(pc) = soc_property_port_get(unit, port, spn_PHY_MOD_AUTO_DETECT, 0); 2776 if (MOD_AUTO_DETECT(pc)) { 2777 uint16 data, mask; 2778 2779 LOG_ERROR(BSL_LS_SOC_PHY, 2780 (BSL_META_U(unit, 2781 "PHY84328 module auto detect enabled: u=%d p=%d\n"), 2782 unit, port)); 2783 2784 /* SFP MOD_DETECT enables both SFP and QSFP module detect */ 2785 data = PHY84328_DEV1_GP_REG_0_ENABLE_SFP_MOD_DETECT_MASK; 2786 mask = PHY84328_DEV1_GP_REG_0_ENABLE_SFP_MOD_DETECT_MASK; 2787 2788 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, data, mask); 2789 if (SOC_FAILURE(rv)) { 2790 MOD_AUTO_DETECT(pc) = 0; 2791 LOG_ERROR(BSL_LS_SOC_PHY, 2792 (BSL_META_U(unit, 2793 "PHY84328 setting module auto detect failed: u=%d p%d\n"), 2794 unit, port)); 2795 } 2796 } 2797 2798 if (soc_property_port_get(unit, port, "phy_84328_port_4_5_control", 0)) { 2799 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, 2800 PHY84328_DEV1_GP_REG_0_P4_5_CTRL, 2801 PHY84328_DEV1_GP_REG_0_P4_5_CTRL); 2802 if (SOC_FAILURE(rv)) { 2803 LOG_ERROR(BSL_LS_SOC_PHY, 2804 (BSL_META_U(unit, 2805 "PHY84328 setting p4_5 control failed: u=%d p%d\n"), 2806 unit, port)); 2807 } 2808 } 2809 2810 2811 #ifdef BCM_WARM_BOOT_SUPPORT 2812 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)){ 2813 return _phy_84328_reinit(unit, port); 2814 } 2815 #endif 2816 2817 /* Cold boot code only below this */ 2818 2819 return SOC_E_NONE; 2820 } 2821 2822 /* 2823 * Check if the core has been initialized. This is done by 2824 * looking at all ports which belong to the same core and see 2825 * if any one of them have completed initialization. 2826 * The primary port is used to determine whether the port is 2827 * on the same core as all ports in a core share the primary port. 2828 */ 2829 STATIC int 2830 _phy_84328_core_init_done(int unit, struct phy_driver_s *pd, int primary_port) 2831 { 2832 int rv; 2833 soc_port_t port; 2834 phy_ctrl_t *pc; 2835 uint32 core_primary_port; 2836 2837 PBMP_ALL_ITER(unit, port) { 2838 pc = EXT_PHY_SW_STATE(unit, port); 2839 if (pc == NULL) { 2840 continue; 2841 } 2842 /* Make sure this port has a 84328 driver */ 2843 if (pc->pd != pd) { 2844 continue; 2845 } 2846 rv = phy_84328_control_port_get(unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 2847 &core_primary_port); 2848 if (rv != SOC_E_NONE) { 2849 continue; 2850 } 2851 if ((primary_port == core_primary_port) && (pc->flags & PHYCTRL_INIT_DONE)) { 2852 return TRUE; 2853 } 2854 } 2855 return FALSE; 2856 } 2857 2858 STATIC int 2859 _phy_84328_init_pass1(int unit, soc_port_t port) 2860 { 2861 phy_ctrl_t *pc; 2862 int offset; 2863 soc_port_t primary_port; 2864 2865 pc = EXT_PHY_SW_STATE(unit, port); 2866 2867 2868 LOG_INFO(BSL_LS_SOC_PHY, 2869 (BSL_META_U(unit, 2870 "PHY84328 init pass1: u=%d p=%d\n"), unit, port)); 2871 2872 /* Set the primary port & offset */ 2873 if (soc_phy_primary_and_offset_get(unit, port, &primary_port, &offset) != SOC_E_NONE) { 2874 /* 2875 * Derive primary and offset 2876 * There is an assumption lane 0 on first core on the the MDIO 2877 * bus is a primary port 2878 */ 2879 if (PHY84328_SINGLE_PORT_MODE(pc)) { 2880 primary_port = port; 2881 offset = 0; 2882 } else { 2883 primary_port = port - (pc->phy_id & 0x3); 2884 offset = pc->phy_id & 0x3; 2885 } 2886 } 2887 /* set the default values that are valid for many boards */ 2888 SOC_IF_ERROR_RETURN(phy_84328_control_port_set(unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 2889 primary_port)); 2890 2891 SOC_IF_ERROR_RETURN(phy_84328_control_port_set(unit, port,SOC_PHY_CONTROL_PORT_OFFSET, 2892 offset)); 2893 2894 /* 2895 * Since there is a single micro and therefore a single copy of the firmware 2896 * shared among the 4 channels in a core, do not download firmware if in quad 2897 * channel and the other channels are active. 2898 */ 2899 if (PHY84328_SINGLE_PORT_MODE(pc) || 2900 (!PHY84328_SINGLE_PORT_MODE(pc) && 2901 (!_phy_84328_core_init_done(unit, pc->pd, primary_port)))) { 2902 uint16 csr_c848 = 0; 2903 2904 /* read Ch. 0 1.C848, bit [13] is download done */ 2905 SOC_IF_ERROR_RETURN( 2906 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 2907 PHY84328_DEV1_SPA_CONTROL_STATUS_REGISTER, 2908 &csr_c848)); 2909 if ((csr_c848 & (1 << 13)) && 2910 !(soc_property_port_get(unit, port, 2911 spn_PHY_FORCE_FIRMWARE_LOAD, TRUE))) { 2912 uint8 *fw_ptr = NULL; 2913 int fw_length = 0; 2914 uint16 chip_micro_ver = 0, file_micro_ver = 0; 2915 2916 SOC_IF_ERROR_RETURN( 2917 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 2918 PHY84328_SYS_DEV1_VERSION, 2919 &chip_micro_ver)); 2920 if (pc->dev_name == dev_name_84328_a0) { 2921 fw_ptr = phy84328_ucode_bin; 2922 fw_length = phy84328_ucode_bin_len; 2923 } else if (pc->dev_name == dev_name_84328) { 2924 fw_ptr = phy84328B0_ucode_bin; 2925 fw_length = phy84328B0_ucode_bin_len; 2926 } else if (pc->dev_name == dev_name_84088) { 2927 fw_ptr = phy84328B0_ucode_bin; 2928 fw_length = phy84328B0_ucode_bin_len; 2929 } else { 2930 /* for other device donot take micro version*/ 2931 pc->flags &= (~PHYCTRL_MDIO_BCST); 2932 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) { 2933 /* indicate second pass of init is needed */ 2934 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS2); 2935 } 2936 return SOC_E_NONE; 2937 } 2938 /* MICRO version is reterived from 4th and 3rd last byte of micro file*/ 2939 file_micro_ver = (fw_ptr[fw_length-4] << 8) | (fw_ptr[fw_length-3]); 2940 if (file_micro_ver != chip_micro_ver) { 2941 pc->flags |= PHYCTRL_MDIO_BCST; 2942 } else { 2943 pc->flags &= (~PHYCTRL_MDIO_BCST); 2944 } 2945 2946 /* 2947 LOG_CLI((BSL_META_U(unit, 2948 "84328 u=%d p=%d skip fw download\n"), unit, port)); 2949 */ 2950 } else { 2951 pc->flags |= PHYCTRL_MDIO_BCST; 2952 } 2953 } 2954 2955 LOG_INFO(BSL_LS_SOC_PHY, 2956 (BSL_META_U(unit, 2957 "phy_84328_init: u=%d p=%d setting primary=%d offset=%d\n"), 2958 unit, port, primary_port, offset)); 2959 2960 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) { 2961 /* indicate second pass of init is needed */ 2962 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS2); 2963 } 2964 2965 return SOC_E_NONE; 2966 } 2967 2968 /* Function: 2969 * phy_84328_init 2970 * Purpose: 2971 * Initialize 84328 phys 2972 * Parameters: 2973 * unit - StrataSwitch unit #. 2974 * port - StrataSwitch port #. 2975 * Returns: 2976 * SOC_E_NONE 2977 */ 2978 2979 STATIC int 2980 _phy_84328_init(int unit, soc_port_t port) 2981 { 2982 int ix; 2983 uint16 data; 2984 uint32 devid; 2985 phy_ctrl_t *pc; 2986 2987 pc = EXT_PHY_SW_STATE(unit, port); 2988 2989 LOG_INFO(BSL_LS_SOC_PHY, 2990 (BSL_META_U(unit, 2991 "PHY84328 init: u=%d p=%d state=%d\n"), 2992 unit, port,PHYCTRL_INIT_STATE(pc))); 2993 2994 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 2995 2996 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) || 2997 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 2998 2999 /* Read the chip id to identify the device */ 3000 SOC_IF_ERROR_RETURN(_phy_84328_config_devid(unit, port, pc, &devid)); 3001 3002 /* Save it in the device description structure for future use */ 3003 DEVID(pc) = devid; 3004 3005 /* initialize default p2l map */ 3006 for (ix = 0; ix < PHY84328_NUM_LANES; ix++) { 3007 P2L_MAP(pc,ix) = ix; 3008 } 3009 3010 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER | PHY_FLAGS_C45 | PHY_FLAGS_REPEATER); 3011 data = (PHY84328_SINGLE_PORT_MODE(pc)) ? 3012 PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK : 0; 3013 SOC_IF_ERROR_RETURN 3014 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 3015 PHY84328_DEV1_SINGLE_PMD_CTRL, data, 3016 PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK)); 3017 3018 SOC_IF_ERROR_RETURN(_phy_84328_init_pass1(unit, port)); 3019 3020 if (PHYCTRL_INIT_STATE(pc) != PHYCTRL_INIT_STATE_DEFAULT) { 3021 return SOC_E_NONE; 3022 } 3023 3024 } 3025 3026 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) || 3027 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 3028 3029 SOC_IF_ERROR_RETURN( _phy_84328_init_pass2(unit, port)); 3030 3031 LOG_INFO(BSL_LS_SOC_PHY, 3032 (BSL_META_U(unit, 3033 "PHY84328 init pass2 completed: u=%d p=%d\n"), unit, port)); 3034 3035 if (PHYCTRL_INIT_STATE(pc) != PHYCTRL_INIT_STATE_DEFAULT) { 3036 return SOC_E_NONE; 3037 } 3038 } 3039 3040 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS3) || 3041 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 3042 3043 SOC_IF_ERROR_RETURN( _phy_84328_init_pass3(unit, port)); 3044 3045 LOG_INFO(BSL_LS_SOC_PHY, 3046 (BSL_META_U(unit, 3047 "PHY84328 init pass3 completed: u=%d p=%d\n"), unit, port)); 3048 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_DEFAULT); 3049 return SOC_E_NONE; 3050 } 3051 3052 return SOC_E_NONE; 3053 } 3054 3055 STATIC int 3056 _phy_84328_dev_an_get(int unit, soc_port_t port, int *an, int *an_done) 3057 { 3058 uint16 data; 3059 uint16 dev_an_done_mask; 3060 phy_ctrl_t *pc; 3061 3062 pc = EXT_PHY_SW_STATE(unit, port); 3063 *an = 0; 3064 *an_done = 0; 3065 3066 /* 3067 * 7.0000[12] an enabled 3068 * 1.0097[0] an/training complete. For 40G, per lane status in bits 12,8,4,0 3069 */ 3070 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_AN_REG(unit, pc, 3071 PHY84328_DEV7_AN_CONTROL_REGISTER, &data)); 3072 *an = (data & PHY84328_DEV7_AN_CONTROL_REGISTER_AUTO_NEGOTIATIONENABLE_MASK) == 3073 PHY84328_DEV7_AN_CONTROL_REGISTER_AUTO_NEGOTIATIONENABLE_MASK; 3074 3075 if (*an) { 3076 SOC_IF_ERROR_RETURN( 3077 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_BASE_R_PMD_STATUS_REGISTER, 3078 &data)); 3079 dev_an_done_mask = PHY84328_SINGLE_PORT_MODE(pc) ? 0x1111 : 0x0001; 3080 *an_done = (data & dev_an_done_mask) == dev_an_done_mask; 3081 } 3082 3083 return SOC_E_NONE; 3084 } 3085 3086 /* 3087 * Function: 3088 * phy_84328_an_get 3089 * Purpose: 3090 * Get the current auto-negotiation status (enabled/busy) 3091 * Parameters: 3092 * unit - StrataSwitch unit #. 3093 * port - StrataSwitch port #. 3094 * an - (OUT) if true, auto-negotiation is enabled. 3095 * an_done - (OUT) if true, auto-negotiation is complete. This 3096 * value is undefined if an == false. 3097 * Returns: 3098 * SOC_E_XXX 3099 */ 3100 3101 STATIC int 3102 phy_84328_an_get(int unit, soc_port_t port, int *an, int *an_done) 3103 { 3104 phy_ctrl_t *pc, *int_pc; 3105 phy84328_intf_cfg_t *line_intf; 3106 3107 pc = EXT_PHY_SW_STATE(unit, port); 3108 int_pc = INT_PHY_SW_STATE(unit, port); 3109 line_intf = &(LINE_INTF(pc)); 3110 3111 if ((line_intf->type == SOC_PORT_IF_GMII) || (line_intf->type == SOC_PORT_IF_SGMII)) { 3112 SOC_IF_ERROR_RETURN(PHY_AUTO_NEGOTIATE_GET(int_pc->pd, unit, port, an, an_done)); 3113 } else { 3114 switch (line_intf->type) { 3115 case SOC_PORT_IF_KX: 3116 case SOC_PORT_IF_KR: 3117 case SOC_PORT_IF_KR4: 3118 case SOC_PORT_IF_CR4: 3119 SOC_IF_ERROR_RETURN(_phy_84328_dev_an_get(unit, port, an, an_done)); 3120 break; 3121 default: 3122 *an = 0; 3123 *an_done = 0; 3124 break; 3125 } 3126 } 3127 3128 LOG_INFO(BSL_LS_SOC_PHY, 3129 (BSL_META_U(unit, 3130 "phy_84328_an_get: u=%d p=%d an=%d\n"), unit, port, *an)); 3131 return SOC_E_NONE; 3132 } 3133 3134 /* 3135 * Function: 3136 * phy_84328_an_set 3137 * Purpose: 3138 * Enable or disabled auto-negotiation on the specified port. 3139 * Parameters: 3140 * unit - StrataSwitch unit #. 3141 * port - StrataSwitch port #. 3142 * an - Boolean, if true, auto-negotiation is enabled 3143 * (and/or restarted). If false, autonegotiation is disabled. 3144 * Returns: 3145 * SOC_E_XXX 3146 */ 3147 STATIC int 3148 _phy_84328_an_set(int unit, soc_port_t port, int an) 3149 { 3150 int dev_an, dev_an_done; 3151 phy_ctrl_t *pc, *int_pc; 3152 phy84328_intf_cfg_t *line_intf; 3153 3154 pc = EXT_PHY_SW_STATE(unit, port); 3155 int_pc = INT_PHY_SW_STATE(unit, port); 3156 line_intf = &(LINE_INTF(pc)); 3157 3158 LOG_INFO(BSL_LS_SOC_PHY, 3159 (BSL_META_U(unit, 3160 "phy_84328_an_set: u=%d p=%d an=%s\n"), 3161 unit, port, an ? "enable" : "disable")); 3162 3163 3164 /* 3165 * Determining line side AN status 3166 * SR/LR/SR4/LR4/CR/CR2/SR2: no AN 3167 * KR/KR4/KR2: line side: cl73/cl72, system side as forced cl72 3168 * CR4: if AN disabled, set interface to 40G CR4 DAC(aka XLAUI_DFE), otherwise, CR4 3169 * GMII: AN handled by internal SerDes 3170 */ 3171 switch (line_intf->type) { 3172 case SOC_PORT_IF_GMII: 3173 case SOC_PORT_IF_SGMII: 3174 AN_EN(pc) = an; 3175 SOC_IF_ERROR_RETURN(PHY_AUTO_NEGOTIATE_SET(int_pc->pd, unit, port, an)); 3176 break; 3177 3178 case SOC_PORT_IF_KX: 3179 case SOC_PORT_IF_KR: 3180 case SOC_PORT_IF_KR4: 3181 AN_EN(pc) = 1; 3182 break; 3183 3184 case SOC_PORT_IF_CR4: 3185 AN_EN(pc) = an; 3186 break; 3187 default: 3188 /* Interface does not support AN in the firmware so it's always forced */ 3189 AN_EN(pc) = FALSE; 3190 } 3191 SOC_IF_ERROR_RETURN(_phy_84328_intf_type_set(unit, port, line_intf->type, TRUE)); 3192 3193 /* If not passtrhu an, make sure firmware has enabled an */ 3194 if (line_intf->speed > 1000) { 3195 _phy_84328_dev_an_get(unit, port, &dev_an, &dev_an_done); 3196 if (dev_an != AN_EN(pc)) { 3197 /* 3198 LOG_ERROR(BSL_LS_SOC_PHY, 3199 (BSL_META_U(unit, 3200 "84328 device autonegotiation mismatch: u=%d p=%d an=%s\n"), 3201 unit, port, AN_EN(pc) ? "en" : "dis")); 3202 */ 3203 } 3204 } 3205 return SOC_E_NONE; 3206 } 3207 3208 /* 3209 * Function: 3210 * _phy_84328_ability_advert_get 3211 * Purpose: 3212 * Get the current advertisement for auto-negotiation. 3213 * Parameters: 3214 * unit - StrataSwitch unit #. 3215 * port - StrataSwitch port #. 3216 * mode - (OUT) Port mode mask indicating supported options/speeds. 3217 * Returns: 3218 * SOC_E_XXX 3219 * Notes: 3220 * The advertisement is retrieved for the ACTIVE medium. 3221 * No synchronization performed at this level. 3222 */ 3223 3224 STATIC int 3225 _phy_84328_ability_advert_get(int unit, soc_port_t port, 3226 soc_port_ability_t *ability) 3227 { 3228 phy_ctrl_t *pc, *int_pc; 3229 uint16 pause_adv; 3230 soc_port_mode_t mode = 0; 3231 phy84328_intf_cfg_t *line_intf; 3232 3233 if (ability == NULL) { 3234 return SOC_E_PARAM; 3235 } 3236 3237 sal_memset(ability, 0, sizeof(soc_port_ability_t)); 3238 3239 pc = EXT_PHY_SW_STATE(unit, port); 3240 line_intf = &(LINE_INTF(pc)); 3241 if (_phy_84328_intf_line_forced(unit, port, line_intf->type)) { 3242 return SOC_E_NONE; 3243 } 3244 3245 if ((line_intf->type == SOC_PORT_IF_KX) || (line_intf->type == SOC_PORT_IF_GMII)) { 3246 int_pc = INT_PHY_SW_STATE(unit, port); 3247 if (int_pc) { 3248 SOC_IF_ERROR_RETURN(PHY_ABILITY_ADVERT_GET(int_pc->pd, unit, port, ability)); 3249 } 3250 return SOC_E_NONE; 3251 } 3252 3253 if(PHY84328_SINGLE_PORT_MODE(pc)) { 3254 ability->speed_full_duplex = SOC_PA_SPEED_40GB; 3255 } 3256 else { 3257 ability->speed_full_duplex = SOC_PA_SPEED_10GB; 3258 } 3259 SOC_IF_ERROR_RETURN 3260 (READ_PHY84328_MMF_AN_REG(unit, pc, PHY84328_DEV7_AN_ADVERTISEMENT_1_REGISTER, &pause_adv)); 3261 3262 mode = 0; 3263 switch (pause_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) { 3264 case CL73_AN_ADV_PAUSE: 3265 mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 3266 break; 3267 case CL73_AN_ADV_ASYM_PAUSE: 3268 mode = SOC_PA_PAUSE_TX; 3269 break; 3270 case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE: 3271 mode = SOC_PA_PAUSE_RX; 3272 break; 3273 default: 3274 mode = 0; 3275 break; 3276 } 3277 ability->pause = mode; 3278 3279 LOG_INFO(BSL_LS_SOC_PHY, 3280 (BSL_META_U(unit, 3281 "phy_84328_ability_advert_get: u=%d p=%d speed(FD)=0x%x pause=0x%x\n"), 3282 unit, port, ability->speed_full_duplex, ability->pause)); 3283 return SOC_E_NONE; 3284 } 3285 3286 /* 3287 * Function: 3288 * _phy_84328_ability_remote_get 3289 * Purpose: 3290 * Get the device's complete abilities. 3291 * Parameters: 3292 * unit - StrataSwitch unit #. 3293 * port - StrataSwitch port #. 3294 * ability - return device's abilities. 3295 * Returns: 3296 * SOC_E_XXX 3297 */ 3298 3299 STATIC int 3300 _phy_84328_ability_remote_get(int unit, soc_port_t port, 3301 soc_port_ability_t *ability) 3302 { 3303 int an, an_done; 3304 uint16 pause_adv; 3305 soc_port_mode_t mode; 3306 phy_ctrl_t *pc, *int_pc; 3307 phy84328_intf_cfg_t *line_intf; 3308 3309 if (ability == NULL) { 3310 return SOC_E_PARAM; 3311 } 3312 3313 /* Only firmware has visibility into remote ability */ 3314 sal_memset(ability, 0, sizeof(soc_port_ability_t)); 3315 3316 pc = EXT_PHY_SW_STATE(unit, port); 3317 line_intf = &(LINE_INTF(pc)); 3318 3319 if (_phy_84328_intf_line_forced(unit, port, line_intf->type)) { 3320 return SOC_E_NONE; 3321 } 3322 3323 if ((line_intf->type == SOC_PORT_IF_KX) || (line_intf->type == SOC_PORT_IF_GMII)) { 3324 int_pc = INT_PHY_SW_STATE(unit, port); 3325 if (int_pc) { 3326 SOC_IF_ERROR_RETURN(PHY_ABILITY_REMOTE_GET(int_pc->pd, unit, port, ability)); 3327 } 3328 return SOC_E_NONE; 3329 } 3330 3331 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 3332 3333 mode = 0; 3334 /* Return what the firmware is setting */ 3335 /* If an done, then return the speed for the port */ 3336 SOC_IF_ERROR_RETURN(phy_84328_an_get(unit, port, &an, &an_done)); 3337 if (an && an_done) { 3338 if(PHY84328_SINGLE_PORT_MODE(pc)) { 3339 ability->speed_full_duplex = SOC_PA_SPEED_40GB; 3340 } 3341 else { 3342 ability->speed_full_duplex = SOC_PA_SPEED_10GB; 3343 } 3344 3345 mode = 0; 3346 SOC_IF_ERROR_RETURN 3347 (READ_PHY84328_MMF_AN_REG(unit, pc, PHY84328_DEV7_AN_LP_BASE_PAGE_ABILITY_1_REG, &pause_adv)); 3348 switch (pause_adv & (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE)) { 3349 case CL73_AN_ADV_PAUSE: 3350 mode = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 3351 break; 3352 case CL73_AN_ADV_ASYM_PAUSE: 3353 mode = SOC_PA_PAUSE_TX; 3354 break; 3355 case CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE: 3356 mode = SOC_PA_PAUSE_RX; 3357 break; 3358 } 3359 ability->pause = mode; 3360 } 3361 LOG_INFO(BSL_LS_SOC_PHY, 3362 (BSL_META_U(unit, 3363 "phy_84328_ability_remote_get: u=%d p=%d speed(FD)=0x%x pause=0x%x\n"), 3364 unit, port, ability->speed_full_duplex, ability->pause)); 3365 return SOC_E_NONE; 3366 } 3367 3368 /* 3369 * Function: 3370 * _phy_84328_ability_advert_set 3371 * Purpose: 3372 * Set the current advertisement for auto-negotiation. 3373 * Parameters: 3374 * unit - StrataSwitch unit #. 3375 * port - StrataSwitch port #. 3376 * mode - Port mode mask indicating supported options/speeds. 3377 * Returns: 3378 * SOC_E_XXX 3379 * Notes: 3380 * The advertisement is set only for the ACTIVE medium. 3381 * No synchronization performed at this level. 3382 */ 3383 3384 STATIC int 3385 _phy_84328_ability_advert_set(int unit, soc_port_t port, 3386 soc_port_ability_t *ability) 3387 { 3388 uint16 pause; 3389 phy_ctrl_t *pc, *int_pc; 3390 phy84328_intf_cfg_t *line_intf; 3391 3392 if (ability == NULL) { 3393 return SOC_E_PARAM; 3394 } 3395 3396 pc = EXT_PHY_SW_STATE(unit, port); 3397 line_intf = &(LINE_INTF(pc)); 3398 if ((line_intf->type == SOC_PORT_IF_KX) || (line_intf->type == SOC_PORT_IF_GMII)) { 3399 int_pc = INT_PHY_SW_STATE(unit, port); 3400 if (int_pc) { 3401 SOC_IF_ERROR_RETURN(PHY_ABILITY_ADVERT_SET(int_pc->pd, unit, port, ability)); 3402 } 3403 return SOC_E_NONE; 3404 } 3405 3406 /* 3407 * Advertisement mostly handled by firmware depending on the mode 3408 * However, the firmware will honor the pause advertisement set by the driver 3409 */ 3410 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 3411 case SOC_PA_PAUSE_TX: 3412 pause = CL73_AN_ADV_ASYM_PAUSE; 3413 break; 3414 case SOC_PA_PAUSE_RX: 3415 pause = CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE; 3416 break; 3417 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 3418 pause = CL73_AN_ADV_PAUSE; 3419 break; 3420 default: 3421 pause = 0; 3422 break; 3423 } 3424 3425 SOC_IF_ERROR_RETURN 3426 (MODIFY_PHY84328_MMF_AN_REG(unit, pc, PHY84328_DEV7_AN_ADVERTISEMENT_1_REGISTER, 3427 pause, (CL73_AN_ADV_PAUSE | CL73_AN_ADV_ASYM_PAUSE))); 3428 3429 LOG_INFO(BSL_LS_SOC_PHY, 3430 (BSL_META_U(unit, 3431 "phy_84328_ability_advert_set: u=%d p=%d speed(FD)=%x pause=0x%x\n"), 3432 unit, port, ability->speed_full_duplex, ability->pause)); 3433 return SOC_E_NONE; 3434 } 3435 3436 /* 3437 * Function: 3438 * phy_84328_ability_local_get 3439 * Purpose: 3440 * Get the device's complete abilities. 3441 * Parameters: 3442 * unit - StrataSwitch unit #. 3443 * port - StrataSwitch port #. 3444 * ability - return device's abilities. 3445 * Returns: 3446 * SOC_E_XXX 3447 */ 3448 3449 STATIC int 3450 phy_84328_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 3451 { 3452 uint32 pa_speed = 0; 3453 phy_ctrl_t *pc; 3454 3455 pc = EXT_PHY_SW_STATE(unit, port); 3456 3457 if (ability == NULL) { 3458 return SOC_E_PARAM; 3459 } 3460 sal_memset(ability, 0, sizeof(soc_port_ability_t)); 3461 3462 if (PHY84328_MULTI_CORE_MODE(pc)) { 3463 pa_speed = SOC_PA_SPEED_100GB; 3464 } else { 3465 pa_speed = PHY84328_SINGLE_PORT_MODE(pc) ? 3466 (SOC_PA_SPEED_40GB | SOC_PA_SPEED_42GB) : 3467 (SOC_PA_SPEED_10GB | SOC_PA_SPEED_1000MB | SOC_PA_SPEED_100MB | SOC_PA_SPEED_10MB); 3468 } 3469 3470 ability->speed_full_duplex = pa_speed; 3471 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 3472 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 3473 ability->interface = SOC_PA_INTF_XGMII; 3474 ability->medium = SOC_PA_MEDIUM_FIBER; 3475 ability->loopback = SOC_PA_LB_PHY; 3476 ability->flags = SOC_PA_AUTONEG; 3477 3478 LOG_INFO(BSL_LS_SOC_PHY, 3479 (BSL_META_U(unit, 3480 "phy_84328_ability_local_get: u=%d p=%d speed=0x%x\n"), 3481 unit, port, ability->speed_full_duplex)); 3482 3483 return SOC_E_NONE; 3484 } 3485 3486 STATIC int 3487 _phy_84328_mod_auto_detect_speed_check(int unit, soc_port_t port, uint16 csr) 3488 { 3489 uint16 csr_speed; 3490 phy_ctrl_t *pc; 3491 phy84328_intf_cfg_t *line_intf; 3492 static int speed_tbl[] = { 0, 1000, 10000, 1000, 40000, 0, 0 ,0, 10000 }; 3493 3494 pc = EXT_PHY_SW_STATE(unit, port); 3495 line_intf = &(LINE_INTF(pc)); 3496 3497 csr_speed = csr & (PHY84328_DEV1_GP_REGISTER_1_SPEED_100G_MASK | 3498 PHY84328_DEV1_GP_REGISTER_1_SPEED_40G_MASK | 3499 PHY84328_DEV1_GP_REGISTER_1_SPEED_10G_MASK | 3500 PHY84328_DEV1_GP_REGISTER_1_SPEED_1G_MASK); 3501 if (line_intf->speed != speed_tbl[csr_speed]) { 3502 LOG_ERROR(BSL_LS_SOC_PHY, 3503 (BSL_META_U(unit, 3504 "84328 module auto detection unexpected: u=%d p=%d csr=0x%x " 3505 "csr table speed=%d line speed=%d\n"), 3506 unit, port, csr, speed_tbl[csr_speed], line_intf->speed)); 3507 } 3508 return (line_intf->speed == speed_tbl[csr_speed]); 3509 } 3510 3511 STATIC int 3512 _phy_84328_mod_auto_detect_intf_process(int unit, soc_port_t port, uint16 csr) 3513 { 3514 int copper_mod = 0; 3515 int lr_mod = 0; 3516 phy_ctrl_t *pc; 3517 phy84328_intf_cfg_t *line_intf; 3518 int intf_update = 1; 3519 3520 pc = EXT_PHY_SW_STATE(unit, port); 3521 line_intf = &(LINE_INTF(pc)); 3522 3523 copper_mod = (csr & PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_MASK) == 3524 PHY84328_DEV1_GP_REGISTER_1_LINE_CU_TYPE_MASK; 3525 3526 lr_mod = (csr & PHY84328_DEV1_GP_REGISTER_1_LINE_LR_MODE_MASK) == 3527 PHY84328_DEV1_GP_REGISTER_1_LINE_LR_MODE_MASK; 3528 3529 /* Change interface if going from optical to copper */ 3530 if (copper_mod) { 3531 switch (line_intf->type) { 3532 case SOC_PORT_IF_SR: 3533 case SOC_PORT_IF_SFI: 3534 case SOC_PORT_IF_XFI: 3535 line_intf->type = SOC_PORT_IF_CR; 3536 break; 3537 case SOC_PORT_IF_SR4: 3538 case SOC_PORT_IF_XLAUI: 3539 line_intf->type = SOC_PORT_IF_CR4; 3540 break; 3541 default: 3542 /* No interface change if not currently an optical interface */ 3543 intf_update = 0; 3544 break; 3545 } 3546 } else { 3547 /* Change interface if going from optical SR to LR */ 3548 if (lr_mod) { 3549 switch (line_intf->type) { 3550 case SOC_PORT_IF_SR: 3551 case SOC_PORT_IF_SFI: 3552 case SOC_PORT_IF_XFI: 3553 line_intf->type = SOC_PORT_IF_LR; 3554 break; 3555 case SOC_PORT_IF_SR4: 3556 case SOC_PORT_IF_XLAUI: 3557 line_intf->type = SOC_PORT_IF_LR4; 3558 break; 3559 default: 3560 /* No interface change */ 3561 intf_update = 0; 3562 break; 3563 } 3564 } 3565 /* Change interface if going from copper to optical */ 3566 switch (line_intf->type) { 3567 case SOC_PORT_IF_CR: 3568 line_intf->type = lr_mod ? SOC_PORT_IF_LR : SOC_PORT_IF_SR; 3569 break; 3570 case SOC_PORT_IF_CR4: 3571 line_intf->type = lr_mod ? SOC_PORT_IF_LR4 : SOC_PORT_IF_SR4; 3572 break; 3573 default: 3574 intf_update = 0; 3575 break; 3576 } 3577 } 3578 if (intf_update) { 3579 SOC_IF_ERROR_RETURN(_phy_84328_intf_line_sys_update(unit, port)); 3580 } 3581 return SOC_E_NONE; 3582 } 3583 3584 STATIC int 3585 _phy_84328_mod_auto_detect_process(int unit, soc_port_t port, uint16 csr) 3586 { 3587 3588 LOG_ERROR(BSL_LS_SOC_PHY, 3589 (BSL_META_U(unit, 3590 "PHY84328 module detected: u=%d p=%d csr=%x\n"), 3591 unit, port, csr)); 3592 3593 /* 3594 * Speed cannot change with module detection so it must match the 3595 * currently configured speed 3596 */ 3597 if (!_phy_84328_mod_auto_detect_speed_check(unit, port, csr)) { 3598 return SOC_E_FAIL; 3599 } 3600 3601 /* 3602 * Get the line side interface based on the current interface and the 3603 * detected module 3604 */ 3605 SOC_IF_ERROR_RETURN(_phy_84328_mod_auto_detect_intf_process(unit, port, csr)); 3606 3607 return SOC_E_NONE; 3608 } 3609 3610 3611 3612 STATIC int 3613 _phy_84328_mod_auto_detect_update(int unit, soc_port_t port) 3614 { 3615 phy_ctrl_t *pc; 3616 uint16 ucode_csr; 3617 uint16 drv_csr; 3618 3619 pc = EXT_PHY_SW_STATE(unit, port); 3620 3621 /* 3622 * New module insertion when 1.c843[4] == 1 and 1.c841[4] == 0 3623 */ 3624 SOC_IF_ERROR_RETURN 3625 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_3, &ucode_csr)); 3626 if (ucode_csr & PHY84328_CSR_REG_MODULE_AUTO_DETECT) { 3627 3628 SOC_IF_ERROR_RETURN 3629 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, &drv_csr)); 3630 if (!(drv_csr & PHY84328_CSR_REG_MODULE_AUTO_DETECT)) { 3631 SOC_IF_ERROR_RETURN(_phy_84328_mod_auto_detect_process(unit, port, ucode_csr)); 3632 3633 /* 3634 * Ack firmware that the module insertion has been updated 3635 * 1.c841[4] = 1, 1.c841[7] = 0 3636 */ 3637 SOC_IF_ERROR_RETURN 3638 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, 3639 PHY84328_CSR_REG_MODULE_AUTO_DETECT, 3640 PHY84328_CSR_REG_MODULE_AUTO_DETECT | 3641 PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK)); 3642 } 3643 } else { 3644 /* 3645 * New module removal when 1.c843[4] == 0 and 1.c841[4] == 1 3646 */ 3647 SOC_IF_ERROR_RETURN 3648 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, &drv_csr)); 3649 if (drv_csr & PHY84328_CSR_REG_MODULE_AUTO_DETECT) { 3650 3651 /* 3652 * Ack firmware new module removal 1.c841[4] = 0 3653 */ 3654 SOC_IF_ERROR_RETURN 3655 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_1, 3656 0, PHY84328_CSR_REG_MODULE_AUTO_DETECT)); 3657 3658 LOG_ERROR(BSL_LS_SOC_PHY, 3659 (BSL_META_U(unit, 3660 "PHY84328 module removed u=%d p=%d\n"), unit, port)); 3661 } 3662 } 3663 3664 return SOC_E_NONE; 3665 } 3666 3667 STATIC int 3668 _phy_84328_do_rxseq_restart(int unit, soc_port_t port,phy84328_intf_side_t side) 3669 { 3670 uint16 data; 3671 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 3672 3673 PHY_84328_MICRO_PAUSE(unit, port, "rxseq restart1"); 3674 if (side == PHY84328_INTF_SIDE_SYS) { 3675 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 3676 } 3677 SOC_IF_ERROR_RETURN 3678 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_DSC_MISC_CTRL0, 3679 PHY84328_DEV1_DSC_MISC_CTRL0_RXSEQSTART_MASK, 3680 PHY84328_DEV1_DSC_MISC_CTRL0_RXSEQSTART_MASK)); 3681 if (side == PHY84328_INTF_SIDE_SYS) { 3682 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 3683 } 3684 PHY_84328_MICRO_RESUME(unit, port); 3685 3686 sal_udelay(800); 3687 3688 PHY_84328_MICRO_PAUSE(unit, port, "rxseq restart 2"); 3689 if (side == PHY84328_INTF_SIDE_SYS) { 3690 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 3691 } 3692 SOC_IF_ERROR_RETURN 3693 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_DSC_MISC_CTRL0, 3694 &data)); 3695 if (data & PHY84328_DEV1_DSC_MISC_CTRL0_RXSEQSTART_MASK) { 3696 /* 3697 * Usually 1.c21e[15] rx seq start is cleared by the microcode but there are cases when 3698 * them micro won't clear it. 3699 */ 3700 SOC_IF_ERROR_RETURN 3701 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 3702 PHY84328_SYS_DEV1_DSC_MISC_CTRL0, 0, 3703 PHY84328_DEV1_DSC_MISC_CTRL0_RXSEQSTART_MASK)); 3704 } 3705 if (side == PHY84328_INTF_SIDE_SYS) { 3706 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 3707 } 3708 PHY_84328_MICRO_RESUME(unit, port); 3709 3710 return SOC_E_NONE; 3711 } 3712 3713 /* 3714 * Restart rx sequencer 3715 * no_cdr_lanes == 0: all lanes have cdr - rxseq being restarted because pcs not up 3716 * != 0: bitmap of lanes which do not have cdr so restart only those lanes 3717 */ 3718 STATIC int 3719 _phy_84328_rxseq_restart(int unit, soc_port_t port, int no_cdr_lanes) 3720 { 3721 int lane; 3722 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 3723 phy84328_counters_t *counters = &(COUNTERS(pc)); 3724 3725 if (PHY84328_SINGLE_PORT_MODE(pc)) { 3726 if (no_cdr_lanes) { 3727 for (lane=0; lane < 4; lane++) { 3728 if (no_cdr_lanes & (1<<lane)) { 3729 counters->no_cdr++; 3730 /* Select the lane on the line side */ 3731 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, 3732 PHY84328_INTF_SIDE_LINE, lane)); 3733 _phy_84328_do_rxseq_restart(unit, port, 3734 PHY84328_INTF_SIDE_LINE); 3735 } 3736 } 3737 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, 3738 PHY84328_ALL_LANES)); 3739 } 3740 } 3741 3742 if (!no_cdr_lanes) { 3743 SOC_IF_ERROR_RETURN(_phy_84328_do_rxseq_restart(unit, port, 3744 PHY84328_INTF_SIDE_LINE)); 3745 } 3746 return SOC_E_NONE; 3747 } 3748 3749 3750 /* 3751 * Gets rx seq done status 3752 * Returns rx_seq_done status and a lane bitmask for lanes which have sigdet but no rx seq done/cdr locked 3753 */ 3754 STATIC int 3755 _phy_84328_rx_seq_done_cdr_lanes_get(int unit, soc_port_t port, phy84328_intf_side_t side, 3756 uint32 *rx_seq_done, uint32 *no_cdr_lanes) 3757 { 3758 uint16 data; 3759 int lane_end, lane; 3760 uint16 cdr_locked; 3761 phy_ctrl_t *pc; 3762 pc = EXT_PHY_SW_STATE(unit, port); 3763 cdr_locked = 0; 3764 *no_cdr_lanes = 0; 3765 3766 if (side == PHY84328_INTF_SIDE_SYS) { 3767 PHY_84328_MICRO_PAUSE(unit, port, "cdr lanes get"); 3768 } 3769 3770 if (PHY84328_SINGLE_PORT_MODE(pc)) { 3771 lane_end = PHY84328_NUM_LANES; 3772 } 3773 else { 3774 lane_end = 1; 3775 _phy_84328_intf_side_regs_select(unit, port, side); 3776 } 3777 3778 for (lane = 0; lane < lane_end; lane++) { 3779 if (PHY84328_SINGLE_PORT_MODE(pc)) { 3780 /* Select the lane on the line side */ 3781 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, lane)); 3782 } 3783 /* Select SigDet/CDR lock status to be read in anaRxStatus */ 3784 SOC_IF_ERROR_RETURN( 3785 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANARXCONTROL, &data)); 3786 3787 if ((data & PHY84328_SYS_DEV1_ANARXCONTROL_STATUS_SEL_MASK) != 0) { 3788 SOC_IF_ERROR_RETURN( 3789 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 3790 PHY84328_SYS_DEV1_ANARXCONTROL, 0, 3791 PHY84328_SYS_DEV1_ANARXCONTROL_STATUS_SEL_MASK)); 3792 } 3793 3794 SOC_IF_ERROR_RETURN( 3795 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANARXSTATUS, &data)); 3796 3797 /* CDR==RxSeqDone */ 3798 if ((data & PHY84328_DEV1_ANARXSTATUS_RXSTATUS_CDR) == 3799 PHY84328_DEV1_ANARXSTATUS_RXSTATUS_CDR) { 3800 cdr_locked++; 3801 } else if (data & 0x8000) { 3802 /* Sigdet but no cdr lock */ 3803 *no_cdr_lanes |= 1 << lane; 3804 } 3805 } 3806 /* Restore to default single port register access */ 3807 if (PHY84328_SINGLE_PORT_MODE(pc)) { 3808 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, 3809 PHY84328_ALL_LANES)); 3810 } 3811 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 3812 if (side == PHY84328_INTF_SIDE_SYS) { 3813 PHY_84328_MICRO_RESUME(unit, port); 3814 } 3815 3816 *rx_seq_done = (cdr_locked == lane_end); 3817 return SOC_E_NONE; 3818 } 3819 3820 STATIC int 3821 _phy_84328_rx_seq_done_get(int unit, soc_port_t port, phy84328_intf_side_t side, uint32 *rx_seq_done) 3822 { 3823 uint32 no_cdr_lanes; 3824 3825 return _phy_84328_rx_seq_done_cdr_lanes_get(unit, port, side, rx_seq_done, &no_cdr_lanes); 3826 } 3827 3828 STATIC int 3829 _phy_84328_sw_rx_los_check(int unit, soc_port_t port, uint16 link, uint16 *new_link) 3830 { 3831 int pcs_link; 3832 uint8 sys_link; 3833 phy_ctrl_t *pc; 3834 phy84328_sw_rx_los_states_t rx_los_state; 3835 phy84328_sw_rx_los_t *sw_rx_los; 3836 uint32 no_cdr_lanes = 0; 3837 uint32 rx_seq_done = 0; 3838 3839 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 3840 int dbg_flag = 1; 3841 #endif 3842 3843 pc = EXT_PHY_SW_STATE(unit, port); 3844 sw_rx_los = &(SW_RX_LOS(pc)); 3845 3846 #ifdef BCM_WARM_BOOT_SUPPORT 3847 if ( SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit) ) { 3848 *new_link = sw_rx_los->sys_link; 3849 return SOC_E_NONE; 3850 } 3851 #endif 3852 3853 pcs_link = link; 3854 sys_link = sw_rx_los->sys_link; 3855 rx_los_state = sw_rx_los->state; 3856 sw_rx_los->link_status = 0; 3857 no_cdr_lanes = 0; 3858 rx_seq_done = 0; 3859 3860 SOC_IF_ERROR_RETURN( 3861 _phy_84328_rx_seq_done_cdr_lanes_get(unit, port, PHY84328_INTF_SIDE_LINE, 3862 &rx_seq_done, &no_cdr_lanes)); 3863 3864 if (rx_los_state != PHY84328_SW_RX_LOS_IDLE) { 3865 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 3866 LOG_VERBOSE(BSL_LS_SOC_PHY, 3867 (BSL_META_U(unit, 3868 "84328 SRL_IN: u=%d p=%d state=%s pcs_link=%d sys_link=%d link_status=%d " 3869 "rx_seq_done=%d no_cdr_lanes=%x\n"), 3870 unit, port, sw_rx_los_state_names[rx_los_state], pcs_link, sys_link, 3871 sw_rx_los->link_status, rx_seq_done, no_cdr_lanes)); 3872 #endif 3873 } 3874 3875 /* 3876 * Current State: Don't Care 3877 * Next State: IDLE 3878 * If link was previously TRUE and is still true, 3879 * set the state to IDLE 3880 */ 3881 if ((sys_link == TRUE) && (pcs_link == TRUE)) { 3882 rx_los_state = PHY84328_SW_RX_LOS_IDLE; 3883 } 3884 3885 /* 3886 * Current State: IDLE 3887 * Next State: RESET 3888 * If the state was IDLE(link up) but now link is down, 3889 * enter the RESET state 3890 */ 3891 if ((rx_los_state == PHY84328_SW_RX_LOS_IDLE) && (pcs_link == FALSE)) { 3892 rx_los_state = PHY84328_SW_RX_LOS_RESET; 3893 sys_link = FALSE; 3894 } 3895 3896 /* 3897 * Current State: RESET 3898 * Next State: INITIAL_LINK or START_TIMER 3899 * If state is RESET, it's next state could be INITIAL LINK 3900 * or START_TIMER depending upon the pcs_link state 3901 */ 3902 if (rx_los_state == PHY84328_SW_RX_LOS_RESET) { 3903 if ((pcs_link == TRUE) && rx_seq_done) { 3904 rx_los_state = PHY84328_SW_RX_LOS_INITIAL_LINK; 3905 } else if (rx_seq_done) { 3906 rx_los_state = PHY84328_SW_RX_LOS_START_TIMER; 3907 sw_rx_los->ls_ticks = 0; 3908 } 3909 } 3910 if (rx_los_state != PHY84328_SW_RX_LOS_IDLE) { 3911 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 3912 if (dbg_flag == 1) { 3913 LOG_VERBOSE(BSL_LS_SOC_PHY, 3914 (BSL_META_U(unit, 3915 "84328 SRL_UPD: u=%d p=%d state=%s pcs_link=%d sys_link=%d link_status=%d " 3916 "rx_seq_done=%d\n====\n"), 3917 unit, port, sw_rx_los_state_names[rx_los_state], pcs_link, sys_link, 3918 sw_rx_los->link_status, rx_seq_done)); 3919 } 3920 #endif 3921 } 3922 3923 /* Take action depending upon the current state */ 3924 switch (rx_los_state) { 3925 case PHY84328_SW_RX_LOS_IDLE: 3926 /* Do nothing */ 3927 /* Link ON condition */ 3928 break; 3929 3930 case PHY84328_SW_RX_LOS_RESET: 3931 #ifdef SW_RX_LOS_FLAP_CHECK 3932 if (sw_rx_los->fault_report_dis) { 3933 SOC_IF_ERROR_RETURN 3934 (MAC_CONTROL_SET(sw_rx_los->macd, unit, port, 3935 SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, TRUE)); 3936 sw_rx_los->fault_report_dis = 0; 3937 } 3938 #endif 3939 sys_link = FALSE; 3940 break; 3941 3942 case PHY84328_SW_RX_LOS_INITIAL_LINK: 3943 #ifdef SW_RX_LOS_FLAP_CHECK 3944 /* Disable local fault reporting to avoid link flaps untill 3945 * link stablizes 3946 */ 3947 SOC_IF_ERROR_RETURN 3948 (MAC_CONTROL_SET(sw_rx_los->macd, unit, port, 3949 SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, FALSE)); 3950 sw_rx_los->fault_report_dis = 1; 3951 #endif 3952 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 3953 if (dbg_flag == 1) { 3954 LOG_VERBOSE(BSL_LS_SOC_PHY, 3955 (BSL_META_U(unit, 3956 "84328 sw rx los: u=%d p=%d state=%s: restarting RxSeq\n"), 3957 unit, port, sw_rx_los_state_names[rx_los_state])); 3958 } 3959 #endif 3960 sw_rx_los->restarts++; 3961 SOC_IF_ERROR_RETURN(_phy_84328_rxseq_restart(unit, port, no_cdr_lanes)); 3962 3963 /* Skip the link transition for this rx reset */ 3964 sw_rx_los->link_status = 1; 3965 rx_los_state = PHY84328_SW_RX_LOS_LINK; 3966 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 3967 if (dbg_flag == 1) { 3968 LOG_VERBOSE(BSL_LS_SOC_PHY, 3969 (BSL_META_U(unit, 3970 "84328 sw rx los: u=%d p=%d state:%s \n"), 3971 unit, port, sw_rx_los_state_names[rx_los_state])); 3972 } 3973 #endif 3974 break; 3975 3976 case PHY84328_SW_RX_LOS_LINK: 3977 3978 if( pcs_link == TRUE) { 3979 sys_link = TRUE; 3980 sw_rx_los->link_no_pcs = 0; 3981 rx_los_state = PHY84328_SW_RX_LOS_IDLE; 3982 } else { 3983 sw_rx_los->link_no_pcs++; 3984 if (sw_rx_los->link_no_pcs > 20) { 3985 rx_los_state = PHY84328_SW_RX_LOS_RESET; 3986 sw_rx_los->link_no_pcs = 0; 3987 } 3988 } 3989 #ifdef SW_RX_LOS_FLAP_CHECK 3990 /* Enable local fault reporting disabled earlier */ 3991 SOC_IF_ERROR_RETURN 3992 (MAC_CONTROL_SET(sw_rx_los->macd, unit, port, 3993 SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, TRUE)); 3994 sw_rx_los->fault_report_dis = 0; 3995 #endif 3996 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 3997 if (dbg_flag == 1) { 3998 LOG_VERBOSE(BSL_LS_SOC_PHY, 3999 (BSL_META_U(unit, 4000 "84328 sw rx los: u=%d p=%d state:%s \n"), 4001 unit, port, sw_rx_los_state_names[rx_los_state])); 4002 } 4003 #endif 4004 break; 4005 4006 case PHY84328_SW_RX_LOS_START_TIMER: 4007 sw_rx_los->ls_ticks++; 4008 if (pcs_link || (sw_rx_los->ls_ticks > 24)) { 4009 rx_los_state = PHY84328_SW_RX_LOS_RX_RESTART; 4010 sw_rx_los->ls_ticks = 0; 4011 } 4012 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 4013 if (dbg_flag == 1) { 4014 LOG_VERBOSE(BSL_LS_SOC_PHY, 4015 (BSL_META_U(unit, 4016 "84328 sw rx los: u=%d p=%d state:%s \n"), 4017 unit, port, sw_rx_los_state_names[rx_los_state])); 4018 } 4019 #endif 4020 break; 4021 4022 case PHY84328_SW_RX_LOS_RX_RESTART: 4023 #ifdef SW_RX_LOS_FLAP_CHECK 4024 /* 4025 * Disable local fault reporting to avoid link flaps until link stablizes 4026 */ 4027 SOC_IF_ERROR_RETURN 4028 (MAC_CONTROL_SET(sw_rx_los->macd, unit, port, 4029 SOC_MAC_CONTROL_FAULT_LOCAL_ENABLE, FALSE)); 4030 sw_rx_los->fault_report_dis = 1; 4031 #endif 4032 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 4033 if (dbg_flag == 1) { 4034 LOG_VERBOSE(BSL_LS_SOC_PHY, 4035 (BSL_META_U(unit, 4036 "84328 sw rx los: u=%d p=%d state:%s -> restarting RxSeq\n"), 4037 unit, port, sw_rx_los_state_names[rx_los_state])); 4038 } 4039 #endif 4040 sw_rx_los->restarts++; 4041 SOC_IF_ERROR_RETURN(_phy_84328_rxseq_restart(unit, port, no_cdr_lanes)); 4042 4043 if( pcs_link == FALSE) { 4044 rx_los_state = PHY84328_SW_RX_LOS_RESET; 4045 } else { 4046 rx_los_state = PHY84328_SW_RX_LOS_LINK; 4047 } 4048 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 4049 if (dbg_flag == 1) { 4050 LOG_VERBOSE(BSL_LS_SOC_PHY, 4051 (BSL_META_U(unit, 4052 "84328 sw rx los : u=%d p=%d state:%s \n"), 4053 unit, port, sw_rx_los_state_names[rx_los_state])); 4054 } 4055 #endif 4056 /* Skip the link transition for this rx reset */ 4057 sw_rx_los->link_status = 1; 4058 break; 4059 4060 default: 4061 break; 4062 } 4063 4064 sw_rx_los->sys_link = sys_link;; 4065 sw_rx_los->state = rx_los_state; 4066 *new_link = sys_link; 4067 4068 return SOC_E_NONE; 4069 } 4070 4071 /* Return contents of ANARXSTATUS */ 4072 STATIC int 4073 _phy_84328_intf_link_get(int unit, soc_port_t port, uint16 *link) 4074 { 4075 int lane, max_lane; 4076 uint16 data; 4077 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4078 *link = 0; 4079 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4080 max_lane = PHY84328_NUM_LANES; 4081 } 4082 else { 4083 max_lane = 1; 4084 } 4085 for (lane = 0; lane < max_lane; lane++) { 4086 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4087 /* Select the lane on the line side */ 4088 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, lane)); 4089 } 4090 /* Select SigDet/CDR lock status to be read in anaRxStatus */ 4091 SOC_IF_ERROR_RETURN( 4092 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANARXCONTROL, &data)); 4093 if ((data & PHY84328_SYS_DEV1_ANARXCONTROL_STATUS_SEL_MASK) != 0) { 4094 SOC_IF_ERROR_RETURN( 4095 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANARXCONTROL, 4096 0, PHY84328_SYS_DEV1_ANARXCONTROL_STATUS_SEL_MASK)); 4097 } 4098 4099 /* Check if rxSeq Done in any lane */ 4100 SOC_IF_ERROR_RETURN( 4101 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANARXSTATUS, &data)); 4102 if ((data & PHY84328_DEV1_ANARXSTATUS_RXSTATUS_CDR) == 4103 PHY84328_DEV1_ANARXSTATUS_RXSTATUS_CDR) { 4104 *link = 1; 4105 break; 4106 } 4107 } 4108 /* Restore to default single port register access */ 4109 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4110 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, 4111 PHY84328_ALL_LANES)); 4112 } 4113 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4114 4115 return SOC_E_NONE; 4116 } 4117 4118 /* 4119 * Called when there is no link so check different link components and attempt to 4120 * recover by restarting interface if appropriate 4121 */ 4122 STATIC int 4123 _phy_84328_link_recover(int unit, soc_port_t port, int line_link, int int_phy_link) 4124 { 4125 phy_ctrl_t *pc; 4126 phy84328_counters_t *counters; 4127 phy84328_link_mon_t *link_mon; 4128 4129 pc = EXT_PHY_SW_STATE(unit, port); 4130 counters = &(COUNTERS(pc)); 4131 link_mon = &(LINK_MON(pc)); 4132 4133 if (line_link && !int_phy_link) { 4134 if (link_mon->debounce > PHY84328_LINK_DEBOUNCE) { 4135 counters->retry_serdes_link++; 4136 LOG_INFO(BSL_LS_SOC_PHY, 4137 (BSL_META_U(unit, 4138 "84328 restarting intf: u=%d p=%d line=%04x internal=%04x debounce=%d\n"), 4139 unit, port, line_link, int_phy_link, link_mon->debounce)); 4140 SOC_IF_ERROR_RETURN(_phy_84328_intf_line_sys_update(unit, port)); 4141 link_mon->debounce = 0; 4142 } else { 4143 link_mon->debounce++; 4144 } 4145 } else { 4146 link_mon->debounce = 0; 4147 } 4148 4149 return SOC_E_NONE; 4150 } 4151 4152 /* 4153 * Function: 4154 * phy_84328_link_get 4155 * Purpose: 4156 * Get layer2 connection status. 4157 * Parameters: 4158 * unit - StrataSwitch unit #. 4159 * port - StrataSwitch port #. 4160 * link - address of memory to store link up/down state. 4161 * Returns: 4162 * SOC_E_NONE 4163 */ 4164 4165 STATIC int 4166 _phy_84328_link_get(int unit, soc_port_t port, int *link) 4167 { 4168 phy_ctrl_t *pc; 4169 phy_ctrl_t *int_pc; 4170 uint16 line_link; 4171 int int_phy_link; 4172 phy84328_sw_rx_los_t *sw_rx_los; 4173 phy84328_link_mon_t *link_mon; 4174 phy84328_counters_t *counters; 4175 4176 if (link == NULL) { 4177 return SOC_E_NONE; 4178 } 4179 4180 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 4181 *link = 0; 4182 return SOC_E_NONE; 4183 } 4184 4185 pc = EXT_PHY_SW_STATE(unit, port); 4186 int_pc = INT_PHY_SW_STATE(unit, port); 4187 counters = &(COUNTERS(pc)); 4188 4189 /* 4190 * PCS from the internal PHY is used to determine link. 4191 */ 4192 if (int_pc != NULL) { 4193 SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, &int_phy_link)); 4194 *link = int_phy_link; 4195 } else { 4196 *link = 0; 4197 } 4198 4199 sw_rx_los = &(SW_RX_LOS(pc)); 4200 if (sw_rx_los->cur_enable) { 4201 uint16 new_link = 0; 4202 if (_phy_84328_sw_rx_los_check(unit, port, *link, &new_link) != SOC_E_NONE) { 4203 LOG_ERROR(BSL_LS_SOC_PHY, 4204 (BSL_META_U(unit, 4205 "84328 rx los check failed: u=%d port=%d\n"), 4206 unit, port)); 4207 } 4208 *link = new_link; 4209 } 4210 4211 if (CUR_LINK(pc) && (*link == 0)) { 4212 counters->link_down++; 4213 } 4214 CUR_LINK(pc) = *link; 4215 4216 link_mon = &(LINK_MON(pc)); 4217 if (link_mon->cur_enable) { 4218 if (*link) { 4219 link_mon->debounce = 0; 4220 } else { 4221 SOC_IF_ERROR_RETURN(_phy_84328_intf_link_get(unit, port, &line_link)); 4222 if (line_link) { 4223 _phy_84328_link_recover(unit, port, line_link, *link); 4224 } else { 4225 link_mon->debounce = 0; 4226 } 4227 } 4228 } 4229 4230 if (MOD_AUTO_DETECT(pc)) { 4231 _phy_84328_mod_auto_detect_update(unit, port); 4232 } 4233 4234 return SOC_E_NONE; 4235 } 4236 4237 /* 4238 * Function: 4239 * phy_84328_enable_set 4240 * Purpose: 4241 * Enable/Disable phy 4242 * Parameters: 4243 * unit - StrataSwitch unit #. 4244 * port - StrataSwitch port #. 4245 * enable - on/off state to set 4246 * Returns: 4247 * SOC_E_NONE 4248 */ 4249 4250 STATIC int 4251 _phy_84328_enable_set(int unit, soc_port_t port, int enable) 4252 { 4253 uint16 chan_data, chan_mask; 4254 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4255 4256 /* Manually power channel up/down */ 4257 chan_data = enable ? 0 : 4258 (1 << PHY84328_DEV1_OPTICAL_CONFIGURATION_MAN_TXON_EN_SHIFT) | 4259 (1 << PHY84328_DEV1_OPTICAL_CONFIGURATION_TXOFFT_SHIFT); 4260 chan_mask = PHY84328_DEV1_OPTICAL_CONFIGURATION_MAN_TXON_EN_MASK | 4261 PHY84328_DEV1_OPTICAL_CONFIGURATION_TXOFFT_MASK; 4262 SOC_IF_ERROR_RETURN( 4263 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_OPTICAL_CONFIGURATION, 4264 chan_data, chan_mask)); 4265 if (enable) { 4266 /* Let the micro settle down after powering back up */ 4267 if (PORT_ENABLE_DELAY(pc)) { 4268 sal_udelay(PORT_ENABLE_DELAY(pc)); 4269 } 4270 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 4271 } else { 4272 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 4273 } 4274 4275 return SOC_E_NONE; 4276 } 4277 4278 /* 4279 * The microcode automatically squelches tx in 1.c066[10] when opposite side has 4280 * no link. Setting 1.ca18[7] disables the microcode from squelching 4281 */ 4282 STATIC int 4283 _phy_84328_micro_tx_squelch_enable(int unit, soc_port_t port, int enable) 4284 { 4285 uint16 data; 4286 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4287 /* 1.ca18[7] 0=micro squelching enabled, 1=micro squelching disabled */ 4288 data = enable ? 0 : 0x80; 4289 SOC_IF_ERROR_RETURN( 4290 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, data, 0x80)); 4291 return SOC_E_NONE; 4292 4293 } 4294 4295 /* 4296 * Squelch/unsquelch tx in 1.c066[8] 4297 */ 4298 STATIC int 4299 _phy_84328_tx_squelch(int unit, soc_port_t port, phy84328_intf_side_t side, int squelch) 4300 { 4301 uint16 data; 4302 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4303 4304 _phy_84328_intf_side_regs_select(unit, port, side); 4305 4306 /* 1.c066[8] 0=unsquelch, 1=squelch - electrical idle */ 4307 data = squelch ? PHY84328_DEV1_ANATXACONTROL2_TX_ELECTRAL_IDLE : 0; 4308 4309 SOC_IF_ERROR_RETURN( 4310 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL2, 4311 data, 4312 PHY84328_DEV1_ANATXACONTROL2_TX_ELECTRAL_IDLE)); 4313 if (side != PHY84328_INTF_SIDE_LINE) { 4314 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4315 } 4316 return SOC_E_NONE; 4317 } 4318 4319 /* 4320 * Enable/disable transmitter 4321 */ 4322 STATIC int 4323 _phy_84328_tx_enable(int unit, soc_port_t port, phy84328_intf_side_t side, int enable) 4324 { 4325 uint16 data; 4326 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4327 _phy_84328_intf_side_regs_select(unit, port, side); 4328 4329 if (CUR_DATAPATH(pc) == PHY84328_DATAPATH_20) { 4330 /* 1.c06a[0] 0=tx enabled, 1=tx disabled */ 4331 data = enable ? 0 : 4332 (1 << PHY84328_DEV1_ANATXACONTROL6_DISABLE_TRANSMIT_SHIFT); 4333 4334 SOC_IF_ERROR_RETURN( 4335 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 4336 PHY84328_DEV1_ANATXACONTROL6, 4337 data, PHY84328_DEV1_ANATXACONTROL6_DISABLE_TRANSMIT_MASK)); 4338 } else { 4339 /* 1.c068[13] 0=tx enabled, 1=tx disabled */ 4340 data = enable ? 0 : (1 << PHY84328_DEV1_ANATXACONTROL4_XFI_LOWLATENCY_FIFO_ZERO_OUT_SHIFT); 4341 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG( 4342 unit, pc, PHY84328_DEV1_ANATXACONTROL4, data, 4343 PHY84328_DEV1_ANATXACONTROL4_XFI_LOWLATENCY_FIFO_ZERO_OUT_MASK)); 4344 } 4345 if (side != PHY84328_INTF_SIDE_LINE) { 4346 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4347 } 4348 return SOC_E_NONE; 4349 } 4350 4351 STATIC int 4352 _phy_84328_data_path_check(int unit, soc_port_t port) 4353 { 4354 phy_ctrl_t *pc; 4355 phy84328_intf_cfg_t *sys_intf; 4356 4357 pc = EXT_PHY_SW_STATE(unit, port); 4358 sys_intf = &(SYS_INTF(pc)); 4359 4360 if (sys_intf->speed < 10000) { 4361 /* Speeds below 10G requires 20-bit datapath */ 4362 if (CUR_DATAPATH(pc) != PHY84328_DATAPATH_20) { 4363 CUR_DATAPATH(pc) = PHY84328_DATAPATH_20; 4364 SOC_IF_ERROR_RETURN(_phy_84328_intf_datapath_update(unit, port)); 4365 } 4366 } else { 4367 /* Speeds 10G and above can use configured dpath, if !forced 20-bit */ 4368 if (FORCE_20BIT(pc) != 0) { 4369 if (CUR_DATAPATH(pc) != PHY84328_DATAPATH_20) { 4370 CUR_DATAPATH(pc) = PHY84328_DATAPATH_20; 4371 SOC_IF_ERROR_RETURN(_phy_84328_intf_datapath_update(unit, port)); 4372 } 4373 } else { 4374 if (CUR_DATAPATH(pc) != CFG_DATAPATH(pc)) { 4375 CUR_DATAPATH(pc) = CFG_DATAPATH(pc); 4376 SOC_IF_ERROR_RETURN(_phy_84328_intf_datapath_update(unit, port)); 4377 } 4378 } 4379 } 4380 return SOC_E_NONE; 4381 } 4382 4383 /* 4384 * Function: 4385 * phy_84328_lb_set 4386 * Purpose: 4387 * Put 84328 in PHY PMA/PMD loopback 4388 * Parameters: 4389 * unit - StrataSwitch unit #. 4390 * port - StrataSwitch port #. 4391 * enable - binary value for on/off (1/0) 4392 * Returns: 4393 * SOC_E_NONE 4394 */ 4395 4396 STATIC int 4397 _phy_84328_lb_set(int unit, soc_port_t port, int enable) 4398 { 4399 int rv = SOC_E_NONE; 4400 uint16 data, mask; 4401 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4402 SOC_IF_ERROR_RETURN(_phy_84328_sw_rx_los_pause(unit, port, enable)); 4403 SOC_IF_ERROR_RETURN(_phy_84328_link_mon_pause(unit, port, enable)); 4404 4405 /* 4406 * If enabling loopback 4407 * disable tx line 4408 */ 4409 if (enable) { 4410 SOC_IF_ERROR_RETURN(_phy_84328_tx_enable(unit, port, PHY84328_INTF_SIDE_LINE, FALSE )); 4411 } 4412 4413 /* Loopback requires 20-bit datapath */ 4414 FORCE_20BIT(pc) &= ~(FORCE_20BIT_LB); 4415 FORCE_20BIT(pc) |= enable ? FORCE_20BIT_LB : 0; 4416 SOC_IF_ERROR_RETURN(_phy_84328_data_path_check(unit, port)); 4417 4418 /* 4419 * If disabling loopback 4420 * enable tx line 4421 */ 4422 if (!enable) { 4423 SOC_IF_ERROR_RETURN(_phy_84328_tx_enable(unit, port, PHY84328_INTF_SIDE_LINE, TRUE )); 4424 } 4425 4426 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 4427 data = enable ? (1 << PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_SHIFT) : 4428 (1 << PHY84328_DEV1_ANATXACONTROL6_LOWLATENCY_PATH_SELECT_SHIFT); 4429 mask = PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_MASK | 4430 PHY84328_DEV1_ANATXACONTROL6_LOWLATENCY_PATH_SELECT_MASK; 4431 rv = MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANATXACONTROL6, data, mask); 4432 if (SOC_FAILURE(rv)) { 4433 LOG_ERROR(BSL_LS_SOC_PHY, 4434 (BSL_META_U(unit, 4435 "84328 failed setting loopback: u=%d port=%d\n"), unit, port)); 4436 } 4437 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4438 4439 return rv; 4440 } 4441 4442 /* 4443 * Function: 4444 * phy_84328_lb_get 4445 * Purpose: 4446 * Get 84328 PHY loopback state 4447 * Parameters: 4448 * unit - StrataSwitch unit #. 4449 * port - StrataSwitch port #. 4450 * enable - address of location to store binary value for on/off (1/0) 4451 * Returns: 4452 * SOC_E_NONE 4453 */ 4454 4455 STATIC int 4456 _phy_84328_lb_get(int unit, soc_port_t port, int *enable) 4457 { 4458 int rv = SOC_E_NONE; 4459 uint16 data; 4460 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4461 if (NULL == enable) { 4462 return SOC_E_PARAM; 4463 } 4464 *enable = 0xFFFF; 4465 /* Check if rloop in system side */ 4466 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 4467 4468 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANATXACONTROL6, &data); 4469 *enable &= ((data & PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_MASK) == 4470 (1 << PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_SHIFT)); 4471 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4472 4473 return rv; 4474 } 4475 4476 STATIC int 4477 _phy_84328_control_preemphasis_lane_get(soc_phy_control_t type) 4478 { 4479 int lane; 4480 4481 switch (type) { 4482 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 4483 lane = 0; 4484 break; 4485 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 4486 lane = 1; 4487 break; 4488 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 4489 lane = 2; 4490 break; 4491 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 4492 lane = 3; 4493 break; 4494 default: 4495 lane = PHY84328_ALL_LANES; 4496 break; 4497 } 4498 return lane; 4499 } 4500 4501 STATIC int 4502 _phy_84328_control_preemphasis_set(int unit, soc_port_t port, 4503 soc_phy_control_t type, 4504 phy84328_intf_side_t side, 4505 uint32 value) 4506 { 4507 uint16 preemph_value; 4508 int lane, lane_idx, lane_start, lane_end; 4509 uint16 tx_fir_sel, tx_fir_mask; 4510 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4511 lane = _phy_84328_control_preemphasis_lane_get(type); 4512 if (!PHY84328_SINGLE_PORT_MODE(pc) && (lane != PHY84328_ALL_LANES)) { 4513 if (lane != (pc->phy_id & 0x03)) { 4514 return SOC_E_PARAM; 4515 } 4516 } 4517 preemph_value = (uint16) (value & 0xffff); 4518 /* 4519 * Value format: 4520 * bit 15: if set, enable forced preemphasis control, otherwise, auto configured - see 1.c192[3:0] 4521 * bit 13:10: postcursor_tap - see 1.c067[7:4] 4522 * bit 08:04: main_tap - see 1.c066[15:11] 4523 * bit 02:00: precursor_tap - see 1.c067[2:0] 4524 */ 4525 4526 /* 4527 * Single mode: if lane specified, enable only that lane, otherwise enable all lanes 4528 * Quad mode: if specified lane matches lane for the channel, set the lane 4529 */ 4530 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4531 tx_fir_sel = (lane == PHY84328_ALL_LANES) ? 0xf : (1 << lane); 4532 tx_fir_mask = (lane == PHY84328_ALL_LANES) ? PHY84328_DEV1_XFI_AFE_CTL2_TX_FIR_SEL_MASK : 4533 (1 << lane); 4534 } else { 4535 tx_fir_sel = 1 << (pc->phy_id & 0x03); 4536 tx_fir_mask = 1 << (pc->phy_id & 0x03); 4537 } 4538 4539 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4540 lane_start = (lane == PHY84328_ALL_LANES) ? 0 : lane; 4541 lane_end = (lane == PHY84328_ALL_LANES) ? PHY84328_NUM_LANES : lane + 1; 4542 } 4543 else { 4544 /* Make sure specified lane matches lane for the channel */ 4545 if (lane != PHY84328_ALL_LANES) { 4546 if (lane != (pc->phy_id & 0x03)) { 4547 return SOC_E_PARAM; 4548 } 4549 } 4550 lane_start = 0; 4551 lane_end = 1; 4552 } 4553 4554 if (side == PHY84328_INTF_SIDE_SYS) { 4555 PHY_84328_MICRO_PAUSE(unit, port, "preemphasis set"); 4556 } 4557 4558 if (!PHY84328_SINGLE_PORT_MODE(pc)) { 4559 _phy_84328_intf_side_regs_select(unit, port, side); 4560 } 4561 /* Update all requested lanes */ 4562 for (lane_idx = lane_start; lane_idx < lane_end; lane_idx++) { 4563 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4564 /* Select the lane and side to write */ 4565 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, lane_idx)); 4566 } 4567 /* Enable manual preemphasis */ 4568 SOC_IF_ERROR_RETURN( 4569 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_XFI_AFE_CTL2, 4570 tx_fir_sel, tx_fir_mask)); 4571 4572 /* Main tap */ 4573 SOC_IF_ERROR_RETURN( 4574 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL2, 4575 PHY84328_PREEMPH_MAIN_TAP_GET(preemph_value) << 4576 PHY84328_DEV1_ANATXACONTROL2_MAIN_TAP_SHIFT, 4577 PHY84328_DEV1_ANATXACONTROL2_MAIN_TAP_MASK)); 4578 4579 /* Pre and post cursor */ 4580 SOC_IF_ERROR_RETURN( 4581 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL3, 4582 (PHY84328_PREEMPH_POST_TAP_GET(preemph_value) << 4583 PHY84328_DEV1_ANATXACONTROL3_POSTCURSOR_TAP_SHIFT) | 4584 (PHY84328_PREEMPH_PRE_TAP_GET(preemph_value) << 4585 PHY84328_DEV1_ANATXACONTROL3_PRECURSOR_TAP_SHIFT), 4586 (PHY84328_DEV1_ANATXACONTROL3_POSTCURSOR_TAP_MASK | 4587 PHY84328_DEV1_ANATXACONTROL3_PRECURSOR_TAP_MASK))); 4588 } 4589 4590 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4591 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, PHY84328_ALL_LANES)); 4592 } 4593 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4594 if (side == PHY84328_INTF_SIDE_SYS) { 4595 PHY_84328_MICRO_RESUME(unit, port); 4596 } 4597 4598 return SOC_E_NONE; 4599 } 4600 4601 STATIC int 4602 _phy_84328_control_preemphasis_get(int unit, soc_port_t port, soc_phy_control_t type, 4603 phy84328_intf_side_t side, uint32 *value) 4604 { 4605 int lane, lane_idx; 4606 uint16 forced; 4607 uint16 data; 4608 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4609 4610 lane = _phy_84328_control_preemphasis_lane_get(type); 4611 lane_idx = (lane == PHY84328_ALL_LANES) ? 0 : lane; 4612 4613 if (side == PHY84328_INTF_SIDE_SYS) { 4614 PHY_84328_MICRO_PAUSE(unit, port, "preemphasis get"); 4615 } 4616 4617 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4618 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, lane_idx)); 4619 } else { 4620 _phy_84328_intf_side_regs_select(unit, port, side); 4621 } 4622 4623 /* 4624 * Value format: 4625 * bit 15: if set, enable forced preemphasis control, otherwise, auto configured - see 1.c192[3:0] 4626 * bit 13:10: postcursor_tap - see 1.c067[7:4] 4627 * bit 08:04: main_tap - see 1.c066[15:11] 4628 * bit 02:00: precursor_tap - see 1.c067[2:0] 4629 */ 4630 *value = 0; 4631 SOC_IF_ERROR_RETURN( 4632 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_XFI_AFE_CTL2, &data)); 4633 data &= 0xf; 4634 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4635 if (lane == PHY84328_ALL_LANES) { 4636 forced = (data == 0xf) ? 1 : 0; 4637 } else { 4638 forced = (data & (1 << lane)) ? 1 : 0; 4639 } 4640 } else { 4641 forced = (data & (1 << (pc->phy_id & 0x03))) ? 1 : 0; 4642 } 4643 *value = PHY84328_PREEMPH_FORCE_SET(forced); 4644 4645 SOC_IF_ERROR_RETURN( 4646 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL2, &data)); 4647 *value |= PHY84328_PREEMPH_MAIN_TAP_SET((data & PHY84328_DEV1_ANATXACONTROL2_MAIN_TAP_MASK) >> 4648 PHY84328_DEV1_ANATXACONTROL2_MAIN_TAP_SHIFT); 4649 4650 SOC_IF_ERROR_RETURN( 4651 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL3, &data)); 4652 *value |= PHY84328_PREEMPH_POST_TAP_SET((data & PHY84328_DEV1_ANATXACONTROL3_POSTCURSOR_TAP_MASK) >> 4653 PHY84328_DEV1_ANATXACONTROL3_POSTCURSOR_TAP_SHIFT); 4654 *value |= PHY84328_PREEMPH_PRE_TAP_SET((data & PHY84328_DEV1_ANATXACONTROL3_PRECURSOR_TAP_MASK) >> 4655 PHY84328_DEV1_ANATXACONTROL3_PRECURSOR_TAP_SHIFT); 4656 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4657 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, PHY84328_ALL_LANES)); 4658 } 4659 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4660 if (side == PHY84328_INTF_SIDE_SYS) { 4661 PHY_84328_MICRO_RESUME(unit, port); 4662 } 4663 4664 return SOC_E_NONE; 4665 } 4666 4667 STATIC int 4668 _phy_84328_txmode_manual_set(int unit, soc_port_t port, phy84328_intf_side_t side, int set) 4669 { 4670 uint16 data, mask; 4671 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4672 phy84328_intf_side_t cur_side; 4673 4674 mask = (side == PHY84328_INTF_SIDE_LINE) ? (1 << 4) : (1 << 3); 4675 data = set ? mask : 0; 4676 4677 cur_side = _phy_84328_intf_side_regs_get(unit, port); 4678 if (cur_side == PHY84328_INTF_SIDE_SYS) { 4679 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4680 } 4681 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, 4682 data, mask)); 4683 if (cur_side == PHY84328_INTF_SIDE_SYS) { 4684 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 4685 } 4686 return SOC_E_NONE; 4687 } 4688 4689 STATIC int 4690 _phy_84328_control_tx_driver_set(int unit, soc_port_t port, soc_phy_control_t type, 4691 phy84328_intf_side_t side, uint32 value) 4692 { 4693 uint16 data, mask; 4694 int lane, lane_idx, lane_start, lane_end; 4695 int idriver = 0; 4696 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4697 4698 switch (type) { 4699 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 4700 lane = 0; 4701 data = (uint16) (value & 0xf); 4702 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4703 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4704 idriver = 1; 4705 break; 4706 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 4707 lane = 1; 4708 data = (uint16) (value & 0xf); 4709 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4710 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4711 idriver = 1; 4712 break; 4713 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 4714 lane = 2; 4715 data = (uint16) (value & 0xf); 4716 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4717 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4718 idriver = 1; 4719 break; 4720 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 4721 lane = 3; 4722 data = (uint16) (value & 0xf); 4723 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4724 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4725 idriver = 1; 4726 break; 4727 case SOC_PHY_CONTROL_DRIVER_CURRENT: 4728 lane = PHY84328_ALL_LANES; 4729 data = (uint16) (value & 0xf); 4730 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4731 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4732 idriver = 1; 4733 break; 4734 4735 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 4736 lane = 0; 4737 data = (uint16) (value & 0xf); 4738 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4739 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4740 break; 4741 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 4742 lane = 1; 4743 data = (uint16) (value & 0xf); 4744 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4745 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4746 break; 4747 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 4748 lane = 2; 4749 data = (uint16) (value & 0xf); 4750 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4751 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4752 break; 4753 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 4754 lane = 3; 4755 data = (uint16) (value & 0xf); 4756 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4757 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4758 break; 4759 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 4760 lane = PHY84328_ALL_LANES; 4761 data = (uint16) (value & 0xf); 4762 data = data << PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4763 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4764 break; 4765 default: 4766 return SOC_E_PARAM; 4767 } 4768 4769 /* 4770 * Qualify lane 4771 * - single mode: if lane specified, enable only that lane in Single_PMD_Ctrl 1.ca86[5:4], 4772 * otherwise program all lanes 4773 * - quad mode: make sure the lane corresponds to the channel, and program the lane 4774 * - 20G mode: if lane specified, enable only that lane, otherwise program all lanes 4775 */ 4776 4777 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4778 lane_start = (lane == PHY84328_ALL_LANES) ? 0 : lane; 4779 lane_end = (lane == PHY84328_ALL_LANES) ? PHY84328_NUM_LANES : lane + 1; 4780 } 4781 else { 4782 /* Make sure specified lane matches lane for the channel */ 4783 if (lane != PHY84328_ALL_LANES) { 4784 if (lane != (pc->phy_id & 0x03)) { 4785 return SOC_E_PARAM; 4786 } 4787 } 4788 lane_start = 0; 4789 lane_end = 1; 4790 } 4791 4792 /* 4793 * Driver current (idriver) and tx_mode are updated by the firmware by default. 4794 * If driver current is programmed with value != 0, 4795 * the firmware will no longer update driver current and tx_mode. 4796 * Setting driver current to 0 (re)enables firmware update of both driver current and 4797 * tx_mode 4798 */ 4799 if (idriver) { 4800 if (data & PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK) { 4801 SOC_IF_ERROR_RETURN(_phy_84328_txmode_manual_set(unit, port, side, TRUE)); 4802 } else { 4803 SOC_IF_ERROR_RETURN(_phy_84328_txmode_manual_set(unit, port, side, FALSE)); 4804 } 4805 } 4806 if (side == PHY84328_INTF_SIDE_SYS) { 4807 PHY_84328_MICRO_PAUSE(unit, port, "tx driver set"); 4808 } 4809 4810 if (!PHY84328_SINGLE_PORT_MODE(pc)) { 4811 _phy_84328_intf_side_regs_select(unit, port, side); 4812 } 4813 /* Update all requested lanes */ 4814 for (lane_idx = lane_start; lane_idx < lane_end; lane_idx++) { 4815 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4816 /* Select the lane and side to write */ 4817 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, lane)); 4818 } 4819 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 4820 PHY84328_DEV1_ANATXACONTROL1, 4821 data, mask)); 4822 } 4823 4824 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4825 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, PHY84328_ALL_LANES)); 4826 } 4827 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4828 if (side == PHY84328_INTF_SIDE_SYS) { 4829 PHY_84328_MICRO_RESUME(unit, port); 4830 } 4831 4832 return SOC_E_NONE; 4833 } 4834 4835 STATIC int 4836 _phy_84328_control_tx_driver_get(int unit, soc_port_t port, soc_phy_control_t type, 4837 phy84328_intf_side_t side, uint32 *value) 4838 { 4839 int rv; 4840 int lane = 0; 4841 uint16 data, shift, mask; 4842 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4843 4844 switch (type) { 4845 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 4846 lane = 0; 4847 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4848 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4849 break; 4850 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 4851 lane = 1; 4852 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4853 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4854 break; 4855 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 4856 lane = 2; 4857 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4858 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4859 break; 4860 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 4861 lane = 3; 4862 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4863 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4864 break; 4865 case SOC_PHY_CONTROL_DRIVER_CURRENT: 4866 /* Return value for lane 0 */ 4867 lane = 0; 4868 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_SHIFT; 4869 mask = PHY84328_SYS_DEV1_ANATXACONTROL1_IDRIVER_MASK; 4870 break; 4871 4872 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 4873 lane = 0; 4874 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4875 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4876 break; 4877 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 4878 lane = 1; 4879 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4880 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4881 break; 4882 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 4883 lane = 2; 4884 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4885 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4886 break; 4887 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 4888 lane = 3; 4889 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4890 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4891 break; 4892 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 4893 /* Return value for lane 0 */ 4894 lane = 0; 4895 shift = PHY84328_SYS_DEV1_ANATXACONTROL1_IPREDRIVER_SHIFT; 4896 mask = PHY84328_DEV1_ANATXACONTROL1_IPREDRIVER_MASK; 4897 break; 4898 default: 4899 return SOC_E_PARAM; 4900 } 4901 4902 if (side == PHY84328_INTF_SIDE_SYS) { 4903 PHY_84328_MICRO_PAUSE(unit, port, "tx driver get"); 4904 } 4905 4906 /* Select the lane and side to access */ 4907 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4908 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, lane)); 4909 } else { 4910 _phy_84328_intf_side_regs_select(unit, port, side); 4911 } 4912 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL1, &data); 4913 if (SOC_FAILURE(rv)) { 4914 LOG_ERROR(BSL_LS_SOC_PHY, 4915 (BSL_META_U(unit, 4916 "84328 tx driver get failed: u=%d p=%d\n"), unit, port)); 4917 *value = 0xff; 4918 } else { 4919 *value = (data & mask) >> shift; 4920 } 4921 if (PHY84328_SINGLE_PORT_MODE(pc)) { 4922 /* Restore back to channel 0 */ 4923 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, PHY84328_ALL_LANES)); 4924 } 4925 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 4926 4927 if (side == PHY84328_INTF_SIDE_SYS) { 4928 PHY_84328_MICRO_RESUME(unit, port); 4929 } 4930 return SOC_E_NONE; 4931 } 4932 4933 STATIC int 4934 _phy_84328_control_edc_mode_set(int unit, soc_port_t port, uint32 value) 4935 { 4936 return SOC_E_UNAVAIL; 4937 } 4938 4939 /* 4940 * enable/disable syncE recoverd clock for 10G/40G modes. 4941 */ 4942 STATIC int 4943 _phy_84328_control_recovery_clock_set(int unit, soc_port_t port, int enable) 4944 { 4945 return SOC_E_UNAVAIL; 4946 } 4947 4948 /* 4949 * set the frequency of the syncE recoverd clock. 4950 */ 4951 STATIC int 4952 _phy_84328_control_recovery_clock_freq_set(int unit, soc_port_t port, int freq) 4953 { 4954 return SOC_E_UNAVAIL; 4955 } 4956 4957 STATIC int 4958 _phy_84328_control_prbs_tx_invert_data_set(int unit, soc_port_t port, int invert) 4959 { 4960 uint16 data; 4961 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4962 data = invert ? (1 << PHY84328_SYS_DEV1_ANATXACONTROL7_NEW_PRBS_INV_SHIFT) : 0; 4963 /* tx prbs invert in anaTxAControl7 1.c06b */ 4964 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 4965 PHY84328_DEV1_ANATXACONTROL7, data, 4966 PHY84328_SYS_DEV1_ANATXACONTROL7_NEW_PRBS_INV_MASK)); 4967 4968 return SOC_E_NONE; 4969 } 4970 4971 STATIC int 4972 _phy_84328_control_prbs_rx_invert_data_set(int unit, soc_port_t port, int invert) 4973 { 4974 uint16 data; 4975 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4976 4977 4978 data = invert ? (1 << PHY84328_SYS_DEV1_ANARXCONTROL2_PRBS_INV_RX_R_SHIFT) : 0; 4979 /* rx prbs invert in anaRxControl2 1.c0b6 */ 4980 SOC_IF_ERROR_RETURN( 4981 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANARXCONTROL2, data, 4982 PHY84328_SYS_DEV1_ANARXCONTROL2_PRBS_INV_RX_R_MASK)); 4983 return SOC_E_NONE; 4984 } 4985 4986 STATIC int 4987 _phy_84328_control_prbs_polynomial_set(int unit, soc_port_t port, int poly_ctrl, int tx) 4988 { 4989 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 4990 4991 LOG_INFO(BSL_LS_SOC_PHY, 4992 (BSL_META_U(unit, 4993 "84328 prbs polynomial set: u=%d p=%d polynomial=%d\n"), 4994 unit, port, poly_ctrl)); 4995 4996 if (poly_ctrl < 0 || poly_ctrl > 3) { 4997 LOG_ERROR(BSL_LS_SOC_PHY, 4998 (BSL_META_U(unit, 4999 "84328 prbs invalid polynomial: u=%d p=%d polynomial=%d\n"), 5000 unit, port, poly_ctrl)); 5001 return SOC_E_PARAM; 5002 } 5003 /* poly_ctrl: 0==prbs7, 1==prbs15, 2==prbs23, 3==prbs=31 */ 5004 if (tx) { 5005 /* tx prbs polynomial in anaTxAControl7 1.c06b */ 5006 SOC_IF_ERROR_RETURN( 5007 MODIFY_PHY84328_MMF_PMA_PMD_REG( 5008 unit, pc, 5009 PHY84328_DEV1_ANATXACONTROL7, 5010 (poly_ctrl << PHY84328_DEV1_ANATXACONTROL7_LANE_PRBS_ORDER_NEW_B1_0_SHIFT), 5011 PHY84328_SYS_DEV1_ANATXACONTROL7_LANE_PRBS_ORDER_NEW_B1_0_MASK)); 5012 } else { 5013 /* rx prbs polynomial in anaRxControl2 1.c0b6 */ 5014 SOC_IF_ERROR_RETURN( 5015 MODIFY_PHY84328_MMF_PMA_PMD_REG( 5016 unit, pc, 5017 PHY84328_SYS_DEV1_ANARXCONTROL2, 5018 (poly_ctrl << PHY84328_DEV1_ANARXCONTROL2_PRBS_ORDER_RX_R_SHIFT), 5019 PHY84328_SYS_DEV1_ANARXCONTROL2_PRBS_ORDER_RX_R_MASK)); 5020 } 5021 return SOC_E_NONE; 5022 } 5023 5024 STATIC int 5025 _phy_84328_sw_rx_los_pause(int unit, soc_port_t port, int enable) 5026 { 5027 phy_ctrl_t *pc; 5028 phy84328_sw_rx_los_t *sw_rx_los; 5029 5030 #ifdef BCM_WARM_BOOT_SUPPORT 5031 if ( SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit) ) { 5032 return SOC_E_NONE; 5033 } 5034 #endif 5035 5036 pc = EXT_PHY_SW_STATE(unit, port); 5037 sw_rx_los = &(SW_RX_LOS(pc)); 5038 5039 /* Nothing to do if RX LOS not configured */ 5040 if (!sw_rx_los->cfg_enable) { 5041 return SOC_E_NONE; 5042 } 5043 5044 sw_rx_los->cur_enable = !enable; 5045 5046 return SOC_E_NONE; 5047 } 5048 5049 STATIC int 5050 _phy_84328_link_mon_pause(int unit, soc_port_t port, int enable) 5051 { 5052 phy_ctrl_t *pc; 5053 phy84328_link_mon_t *link_mon; 5054 5055 pc = EXT_PHY_SW_STATE(unit, port); 5056 link_mon = &(LINK_MON(pc)); 5057 5058 /* Nothing to do if LINK_MON not configured */ 5059 if (!link_mon->cfg_enable) { 5060 return SOC_E_NONE; 5061 } 5062 5063 link_mon->cur_enable = !enable; 5064 return SOC_E_NONE; 5065 } 5066 5067 5068 STATIC int 5069 _phy_84328_control_prbs_enable_set(int unit, soc_port_t port, int enable) 5070 { 5071 uint16 tx_data, rx_data; 5072 uint16 tx_mask, rx_mask; 5073 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5074 5075 SOC_IF_ERROR_RETURN(_phy_84328_sw_rx_los_pause(unit, port, enable)); 5076 SOC_IF_ERROR_RETURN(_phy_84328_link_mon_pause(unit, port, enable)); 5077 5078 /* Mask enable bits */ 5079 tx_mask = (PHY84328_DEV1_ANATXACONTROL7_SELECT_NEW_PRBS_MASK | 5080 PHY84328_DEV1_ANATXACONTROL7_NEW_PRBS_EN_MASK); 5081 rx_mask = (PHY84328_DEV1_ANARXCONTROL2_PRBS_SEL_RX_R_MASK | 5082 PHY84328_DEV1_ANARXCONTROL2_PRBS_EN_RX_R_MASK); 5083 5084 /* 5085 * PRBS done with 20-bit datapath 5086 */ 5087 if (enable) { 5088 tx_data = (1 << PHY84328_DEV1_ANATXACONTROL7_SELECT_NEW_PRBS_SHIFT) | 5089 (1 << PHY84328_DEV1_ANATXACONTROL7_NEW_PRBS_EN_SHIFT); 5090 rx_data = (1 << PHY84328_DEV1_ANARXCONTROL2_PRBS_EN_RX_R_SHIFT) | 5091 (1 << PHY84328_DEV1_ANARXCONTROL2_PRBS_SEL_RX_R_SHIFT); 5092 if (CFG_DATAPATH(pc) != PHY84328_DATAPATH_20) { 5093 CUR_DATAPATH(pc) = PHY84328_DATAPATH_20; 5094 } 5095 } else { 5096 tx_data = 0; 5097 rx_data = 0; 5098 if (CFG_DATAPATH(pc) != PHY84328_DATAPATH_20) { 5099 CUR_DATAPATH(pc) = CFG_DATAPATH(pc); 5100 } 5101 } 5102 5103 FORCE_20BIT(pc) &= ~(FORCE_20BIT_LB); 5104 FORCE_20BIT(pc) |= enable ? FORCE_20BIT_LB : 0; 5105 /* Update datapath */ 5106 SOC_IF_ERROR_RETURN(_phy_84328_intf_datapath_update(unit, port)); 5107 5108 /* Enable tx prbs in anaTxAcontrol7 1.c06b[6..5] */ 5109 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5110 PHY84328_DEV1_ANATXACONTROL7, 5111 tx_data, tx_mask)); 5112 /* Enable rx prbs in anaRxControl2 1.c0b6[6..5] */ 5113 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5114 PHY84328_SYS_DEV1_ANARXCONTROL2, 5115 rx_data, rx_mask)); 5116 /* 5117 * If enabling prbs 5118 * disable micro tx squelch updates 5119 * unsquelch tx system 5120 * else 5121 * enable micro tx squelch updates 5122 */ 5123 SOC_IF_ERROR_RETURN(_phy_84328_micro_tx_squelch_enable(unit, port, !enable)); 5124 if (enable) { 5125 SOC_IF_ERROR_RETURN(_phy_84328_tx_squelch(unit, port, PHY84328_INTF_SIDE_SYS, 0)); 5126 } 5127 5128 return SOC_E_NONE; 5129 } 5130 5131 STATIC int 5132 _phy_84328_control_prbs_enable_get(int unit, soc_port_t port, uint32 *value) 5133 { 5134 uint16 tx_data, rx_data; 5135 uint16 tx_en, rx_en; 5136 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5137 5138 /* Enable tx prbs in anaTxAcontrol7 1.c06b[6..5] */ 5139 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5140 PHY84328_DEV1_ANATXACONTROL7, 5141 &tx_data)); 5142 /* Enable rx prbs in anaRxControl2 1.c0b6[6..5] */ 5143 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5144 PHY84328_SYS_DEV1_ANARXCONTROL2, 5145 &rx_data)); 5146 5147 /* Mask enable bits */ 5148 tx_data &= (PHY84328_DEV1_ANATXACONTROL7_SELECT_NEW_PRBS_MASK | 5149 PHY84328_DEV1_ANATXACONTROL7_NEW_PRBS_EN_MASK); 5150 rx_data &= (PHY84328_DEV1_ANARXCONTROL2_PRBS_SEL_RX_R_MASK | 5151 PHY84328_DEV1_ANARXCONTROL2_PRBS_EN_RX_R_MASK); 5152 5153 tx_en = (tx_data & 5154 ((1 << PHY84328_DEV1_ANATXACONTROL7_SELECT_NEW_PRBS_SHIFT) | 5155 (1 << PHY84328_DEV1_ANATXACONTROL7_NEW_PRBS_EN_SHIFT))) == 5156 ((1 << PHY84328_DEV1_ANATXACONTROL7_SELECT_NEW_PRBS_SHIFT) | 5157 (1 << PHY84328_DEV1_ANATXACONTROL7_NEW_PRBS_EN_SHIFT)); 5158 5159 rx_en = (rx_data & 5160 ((1 << PHY84328_DEV1_ANARXCONTROL2_PRBS_EN_RX_R_SHIFT) | 5161 (1 << PHY84328_DEV1_ANARXCONTROL2_PRBS_SEL_RX_R_SHIFT))) == 5162 ((1 << PHY84328_DEV1_ANARXCONTROL2_PRBS_EN_RX_R_SHIFT) | 5163 (1 << PHY84328_DEV1_ANARXCONTROL2_PRBS_SEL_RX_R_SHIFT)); 5164 5165 *value = tx_en && rx_en; 5166 5167 return SOC_E_NONE; 5168 } 5169 5170 STATIC int 5171 _phy_84328_control_prbs_polynomial_get(int unit, soc_port_t port, uint32 *value) 5172 { 5173 uint16 data; 5174 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5175 5176 *value = 0; 5177 /* tx prbs polynomial in anaTxAControl7 1.c06b */ 5178 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5179 PHY84328_DEV1_ANATXACONTROL7, 5180 &data)); 5181 data &= PHY84328_SYS_DEV1_ANATXACONTROL7_LANE_PRBS_ORDER_NEW_B1_0_MASK; 5182 *value = data >> PHY84328_DEV1_ANATXACONTROL7_LANE_PRBS_ORDER_NEW_B1_0_SHIFT; 5183 5184 return SOC_E_NONE; 5185 } 5186 5187 STATIC int 5188 _phy_84328_control_prbs_tx_invert_data_get(int unit, soc_port_t port, uint32 *value) 5189 { 5190 uint16 data; 5191 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5192 5193 *value = 0; 5194 /* tx invert in anaTxAControl7 1.c06b */ 5195 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5196 PHY84328_DEV1_ANATXACONTROL7, &data)); 5197 *value = (data & (1 << PHY84328_SYS_DEV1_ANATXACONTROL7_NEW_PRBS_INV_SHIFT)) == 5198 (1 << PHY84328_SYS_DEV1_ANATXACONTROL7_NEW_PRBS_INV_SHIFT); 5199 5200 return SOC_E_NONE; 5201 } 5202 5203 STATIC int 5204 _phy_84328_control_prbs_rx_status_get(int unit, soc_port_t port, phy84328_intf_side_t side, uint32 *value) 5205 { 5206 uint16 data, tmp, lane_idx, lanes; 5207 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5208 if (PHY84328_SINGLE_PORT_MODE(pc)) { 5209 lanes = PHY84328_NUM_LANES; 5210 } 5211 else { 5212 lanes = 1; 5213 } 5214 5215 *value = 0; 5216 5217 for (lane_idx = 0; lane_idx < lanes; lane_idx++) { 5218 if (PHY84328_SINGLE_PORT_MODE(pc)) { 5219 /* Select the lane and side to access */ 5220 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, 5221 side, lane_idx)); 5222 } 5223 /* save anaRxControl 1.c0b1 in tmp*/ 5224 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5225 PHY84328_SYS_DEV1_ANARXCONTROL, &tmp)); 5226 5227 /* Select PRBS status in anaRxControl 1.c0b1 */ 5228 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5229 PHY84328_SYS_DEV1_ANARXCONTROL, 7, 5230 PHY84328_DEV1_ANARXCONTROL_STATUS_SEL_MASK)); 5231 5232 /* Check for rx PRBS lock in anaRxStatus 1.c0b0 */ 5233 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5234 PHY84328_DEV1_ANARXSTATUS, &data)); 5235 5236 /* Restore the old value into anaRxControl 1.c0b1 */ 5237 SOC_IF_ERROR_RETURN(WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5238 PHY84328_SYS_DEV1_ANARXCONTROL, tmp)); 5239 5240 if (data == PHY84328_DEV1_ANARXSTATUS_RXSTATUS_RX_PRBS_LOCK) { 5241 *value |= 0; /* locked and no errors */ 5242 } else if ((data & PHY84328_DEV1_ANARXSTATUS_RXSTATUS_RX_PRBS_LOCK) != 5243 PHY84328_DEV1_ANARXSTATUS_RXSTATUS_RX_PRBS_LOCK) { 5244 *value |= -1; /* no lock */ 5245 } else { 5246 /* locked with errors */ 5247 *value |= data & PHY84328_DEV1_ANARXSTATUS_RXSTATUS_RX_PRBS_ERR_MASK; 5248 } 5249 } 5250 5251 /* Restore to default single port register access */ 5252 if (PHY84328_SINGLE_PORT_MODE(pc)) { 5253 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, 5254 PHY84328_INTF_SIDE_LINE, PHY84328_ALL_LANES)); 5255 } 5256 5257 return SOC_E_NONE; 5258 } 5259 5260 STATIC int 5261 _phy_84328_control_edc_mode_get(int unit, soc_port_t port, uint32 *value) 5262 { 5263 return SOC_E_UNAVAIL; 5264 } 5265 5266 STATIC int 5267 _phy_84328_remote_loopback_set(int unit, soc_port_t port, int intf, uint32 enable) 5268 { 5269 phy_ctrl_t *pc; /* PHY software state */ 5270 uint16 data, mask; 5271 pc = EXT_PHY_SW_STATE(unit, port); 5272 5273 /* 5274 * If enabling remote loopback 5275 * disable tx system side 5276 */ 5277 if (enable) { 5278 SOC_IF_ERROR_RETURN(_phy_84328_tx_enable(unit, port, PHY84328_INTF_SIDE_SYS, FALSE )); 5279 } 5280 /* Loopback requires 20-bit datapath */ 5281 FORCE_20BIT(pc) &= ~(FORCE_20BIT_LB); 5282 FORCE_20BIT(pc) |= enable ? FORCE_20BIT_LB : 0; 5283 SOC_IF_ERROR_RETURN(_phy_84328_data_path_check(unit, port)); 5284 5285 /* 5286 * If disabling loopback 5287 * enable tx system side 5288 */ 5289 if (!enable) { 5290 SOC_IF_ERROR_RETURN(_phy_84328_tx_enable(unit, port, PHY84328_INTF_SIDE_SYS, TRUE )); 5291 } 5292 data = enable ? (1 << PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_SHIFT) : 0; 5293 mask = PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_MASK; 5294 SOC_IF_ERROR_RETURN( 5295 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANATXACONTROL6, data, mask)); 5296 return SOC_E_NONE; 5297 } 5298 5299 STATIC int 5300 _phy_84328_remote_loopback_get(int unit, soc_port_t port, int intf, uint32 *enable) 5301 { 5302 int rv; 5303 phy_ctrl_t *pc; /* PHY software state */ 5304 uint16 data; 5305 5306 pc = EXT_PHY_SW_STATE(unit, port); 5307 5308 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_ANATXACONTROL6, &data); 5309 *enable = (data & PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_MASK) == 5310 PHY84328_SYS_DEV1_ANATXACONTROL6_RLOOP_MASK; 5311 5312 return rv; 5313 } 5314 5315 STATIC int 5316 _phy_84328_debug_info(int unit, soc_port_t port) 5317 { 5318 phy_ctrl_t *pc; 5319 phy_ctrl_t *int_pc; 5320 phy84328_intf_cfg_t *intf; 5321 phy84328_intf_cfg_t *line_intf; 5322 phy84328_intf_cfg_t *sys_intf; 5323 phy84328_counters_t *counters; 5324 phy84328_sw_rx_los_t *sw_rx_los; 5325 phy84328_link_mon_t *link_mon; 5326 phy84328_intf_side_t side, saved_side; 5327 char *rx_los_sts; 5328 soc_port_if_t iif; 5329 int lane; 5330 int ian, ian_done, ilink, ispeed; 5331 uint16 link_sts[PHY84328_NUM_LANES]; 5332 uint16 pol_sts[PHY84328_NUM_LANES]; 5333 uint16 pol_inv_sts[PHY84328_NUM_LANES]; 5334 uint16 tx_drv[PHY84328_NUM_LANES]; 5335 uint16 preemph_main[PHY84328_NUM_LANES]; 5336 uint16 preemph_pre_post[PHY84328_NUM_LANES]; 5337 uint16 preemph_manual[PHY84328_NUM_LANES]; 5338 uint16 data0, data1, data2, data3, data4, data5, data6, data7; 5339 uint32 die_temp; 5340 uint32 primary_port, offset; 5341 uint16 i = 0; 5342 pc = EXT_PHY_SW_STATE(unit, port); 5343 int_pc = INT_PHY_SW_STATE(unit, port); 5344 5345 SOC_IF_ERROR_RETURN(phy_84328_control_port_get(unit, port, SOC_PHY_CONTROL_PORT_PRIMARY, 5346 &primary_port)); 5347 5348 SOC_IF_ERROR_RETURN(phy_84328_control_port_get(unit, port, SOC_PHY_CONTROL_PORT_OFFSET, 5349 &offset)); 5350 5351 /* Access line side registers */ 5352 saved_side = _phy_84328_intf_side_regs_get(unit, port); 5353 if (saved_side == PHY84328_INTF_SIDE_SYS) { 5354 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 5355 } 5356 5357 /* firware rev: 1.c1f0 */ 5358 SOC_IF_ERROR_RETURN 5359 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5360 PHY84328_DEV1_VERSION, &data0)); 5361 5362 /* micro enabled: 1.ca18 */ 5363 SOC_IF_ERROR_RETURN 5364 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5365 PHY84328_DEV1_GP_REG_0, &data1)); 5366 5367 /* die temperature in 1.c1fd */ 5368 SOC_IF_ERROR_RETURN 5369 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5370 PHY84328_DEV1_TEMPERATURE, &data2)); 5371 die_temp = 418 - (((data2 & PHY84328_DEV1_TEMPERATURE_TEMPERATURE_MASK) * 5556) / 10000); 5372 5373 sw_rx_los = &(SW_RX_LOS(pc)); 5374 link_mon = &(LINK_MON(pc)); 5375 rx_los_sts = "dis"; 5376 if (sw_rx_los->cur_enable) { 5377 rx_los_sts = "sw"; 5378 } else if (FW_RX_LOS(pc)) { 5379 rx_los_sts = "fw"; 5380 } 5381 5382 LOG_CLI((BSL_META_U(unit, 5383 "Port %-2d: rev=%d:%d, chiprev=%04x, " 5384 "micro ver(1.%04x)=%04x, micro(1.%04x)=%04x, die temp=%d(C)%s\n" 5385 " pri:offs=%d:%d, mdio=0x%x, datapath=%d, " 5386 "rxLOS=%s, mod auto=%s, sync=%s, link mon=%s\n"), 5387 port, phy84328_maj_rev, phy84328_min_rev, 5388 DEVREV(pc), 5389 PHY84328_DEV1_VERSION, data0, 5390 PHY84328_DEV1_GP_REG_0, data1, 5391 die_temp, 5392 data2 & PHY84328_DEV1_TEMPERATURE_FORCE_TEMPERATURE_MASK ? 5393 "(forced)" : "", 5394 primary_port, offset, pc->phy_id, 5395 CUR_DATAPATH(pc) == PHY84328_DATAPATH_20 ? 20 : 4, 5396 rx_los_sts, 5397 MOD_AUTO_DETECT(pc) ? "en" : "dis", 5398 SYNC_INIT(pc) ? "en" : "dis", 5399 link_mon->cur_enable ? "en" : "dis")); 5400 5401 /* Single PMD control: 1.ca86 */ 5402 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5403 PHY84328_DEV1_SINGLE_PMD_CTRL, &data0)); 5404 5405 /* Broadcast control: 1.c8fe */ 5406 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5407 PHY84328_DEV1_BROADCAST_CTRL, &data1)); 5408 5409 /* AnaPllStatus 1.c050 */ 5410 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5411 PHY84328_DEV1_ANAPLLASTATUS, &data2)); 5412 5413 /* AN 7.0000 */ 5414 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_AN_REG(unit, pc, 5415 PHY84328_DEV7_AN_CONTROL_REGISTER, &data3)); 5416 5417 /* AN done 1.0097 */ 5418 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5419 PHY84328_SYS_DEV1_BASE_R_PMD_STATUS_REGISTER, 5420 &data4)); 5421 5422 /* Regulator control 1.c850 */ 5423 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5424 PHY84328_DEV1_REGUALTOR_CTRL, &data5)); 5425 5426 /* Global intf type/speed - driver csr: 1.c841 */ 5427 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5428 PHY84328_DEV1_GP_REGISTER_1, &data6)); 5429 5430 /* Micro csr 1.c843 */ 5431 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5432 PHY84328_DEV1_GP_REGISTER_3, &data7)); 5433 5434 LOG_CLI((BSL_META_U(unit, 5435 " PMD(1.%04x)=%04x, bcctrl(1.%04x)=%04x, " 5436 "pll(1.%04x)=%04x, an(7.%04x/1.%04x)=%04x/%04x\n" 5437 " regulator(1.%04x)=%04x, drvcsr(1.%04x)=%04x, " 5438 "ucsr(1.%04x)=%04x\n"), 5439 PHY84328_DEV1_SINGLE_PMD_CTRL, data0, 5440 PHY84328_DEV1_BROADCAST_CTRL, data1, 5441 PHY84328_DEV1_ANAPLLASTATUS, data2, 5442 PHY84328_DEV7_AN_CONTROL_REGISTER, 5443 PHY84328_SYS_DEV1_BASE_R_PMD_STATUS_REGISTER, data3, data4, 5444 PHY84328_DEV1_REGUALTOR_CTRL, data5, 5445 PHY84328_DEV1_GP_REGISTER_1, data6, 5446 PHY84328_DEV1_GP_REGISTER_3, data7)); 5447 5448 counters = &(COUNTERS(pc)); 5449 LOG_CLI((BSL_META_U(unit, 5450 " Counters: link down=%d, intf updates=%d, " 5451 "swRxLOS restarts=%d, no cdr=%d, micro nopause=%d\n" 5452 " retry internal=%d, intf chk(speed=%d, " 5453 "type=%d, sel=%d)\n"), 5454 counters->link_down, counters->intf_updates, 5455 sw_rx_los->restarts, 5456 counters->no_cdr, counters->micro_nopause, 5457 counters->retry_serdes_link, 5458 counters->speed_chk_err, counters->intf_chk_err, 5459 counters->side_sel_err)); 5460 5461 /* Interfaces: software, hardware, internal serdes */ 5462 line_intf = &(LINE_INTF(pc)); 5463 sys_intf = &(SYS_INTF(pc)); 5464 5465 for (side = PHY84328_INTF_SIDE_LINE; side <= PHY84328_INTF_SIDE_SYS; side++) { 5466 5467 _phy_84328_intf_side_regs_select(unit, port, side); 5468 5469 /* control: 1.0000 */ 5470 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5471 PHY84328_DEV1_PMD_CONTROL_REGISTER, &data1)); 5472 5473 /* PMD type: 1.0007 */ 5474 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5475 PHY84328_DEV1_PMD_CONTROL_2_REGISTER, &data2)); 5476 5477 /* Loopback 1.c06a */ 5478 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5479 PHY84328_SYS_DEV1_ANATXACONTROL6, &data3)); 5480 5481 /* Tx disable 1.c066 */ 5482 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_ANATXACONTROL2, 5483 &data4)); 5484 5485 /* Tx disable 1.c06a */ 5486 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5487 PHY84328_DEV1_ANATXACONTROL6, 5488 &data5)); 5489 if (PHY84328_SINGLE_PORT_MODE(pc)) { 5490 5491 if (side == PHY84328_INTF_SIDE_SYS) { 5492 PHY_84328_MICRO_PAUSE(unit, port, ""); 5493 } 5494 for (lane = 0; lane < PHY84328_NUM_LANES; lane++) { 5495 5496 /* Select the lane and side to write */ 5497 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, lane)); 5498 5499 /* Link: 1.c0b0 */ 5500 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5501 PHY84328_DEV1_ANARXSTATUS, 5502 &(link_sts[lane]))); 5503 5504 if (CUR_DATAPATH(pc) == PHY84328_DATAPATH_20) { 5505 /* Polarity setting: 1.c061 */ 5506 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5507 PHY84328_SYS_DEV1_ANATXACONTROL, 5508 &(pol_sts[lane]))); 5509 } else { 5510 /* Polarity setting: 1.c068 */ 5511 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5512 PHY84328_SYS_DEV1_ANATXACONTROL4, 5513 &(pol_sts[lane]))); 5514 } 5515 5516 if (side == PHY84328_INTF_SIDE_LINE) { 5517 /* Polarity inversion setting: 1.c0ba[3:2] in the line side */ 5518 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5519 PHY84328_DEV1_GP_REGISTER_RX_INV, 5520 &(pol_inv_sts[lane]))); 5521 } 5522 5523 /* TX driver: 1.c065 */ 5524 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5525 PHY84328_SYS_DEV1_ANATXACONTROL1, 5526 &(tx_drv[lane]))); 5527 /* Preemphasis manual: 1.c192[15] */ 5528 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5529 PHY84328_SYS_DEV1_XFI_AFE_CTL2, 5530 &(preemph_manual[lane]))); 5531 5532 /* Preemphasis main: 1.c066[15:11] */ 5533 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5534 PHY84328_SYS_DEV1_ANATXACONTROL2, 5535 &(preemph_main[lane]))); 5536 5537 /* Preemphasis pre post: 1.c067 */ 5538 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5539 PHY84328_SYS_DEV1_ANATXACONTROL3, 5540 &(preemph_pre_post[lane]))); 5541 } 5542 /* Back to default channel selection through lane 0 */ 5543 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, PHY84328_ALL_LANES)); 5544 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 5545 if (side == PHY84328_INTF_SIDE_SYS) { 5546 PHY_84328_MICRO_RESUME(unit, port); 5547 } 5548 5549 } else { 5550 /* Link: 1.c0b0 */ 5551 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5552 PHY84328_DEV1_ANARXSTATUS, 5553 &(link_sts[i]))); 5554 if (CUR_DATAPATH(pc) == PHY84328_DATAPATH_20) { 5555 /* Polarity setting: 1.c061 */ 5556 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5557 PHY84328_DEV1_ANATXACONTROL, 5558 &(pol_sts[i]))); 5559 } else { 5560 /* Polarity setting: 1.c068 */ 5561 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5562 PHY84328_DEV1_ANATXACONTROL4, 5563 &(pol_sts[i]))); 5564 } 5565 5566 if (side == PHY84328_INTF_SIDE_LINE) { 5567 /* Polarity inversion setting: 1.c0ba[3:2] in the line side */ 5568 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5569 PHY84328_DEV1_GP_REGISTER_RX_INV, 5570 &(pol_inv_sts[i]))); 5571 } 5572 5573 /* TX driver: 1.c065 */ 5574 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5575 PHY84328_SYS_DEV1_ANATXACONTROL1, 5576 &(tx_drv[i]))); 5577 /* Preemphasis manual: 1.c192[15] */ 5578 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5579 PHY84328_SYS_DEV1_XFI_AFE_CTL2, 5580 &(preemph_manual[i]))); 5581 5582 /* Preemphasis main: 1.c066[15:11] */ 5583 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5584 PHY84328_SYS_DEV1_ANATXACONTROL2, 5585 &(preemph_main[i]))); 5586 5587 /* Preemphasis pre post: 1.c067 */ 5588 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 5589 PHY84328_SYS_DEV1_ANATXACONTROL3, 5590 &(preemph_pre_post[i]))); 5591 } 5592 5593 intf = (side == PHY84328_INTF_SIDE_LINE) ? line_intf : sys_intf; 5594 5595 if (PHY84328_SINGLE_PORT_MODE(pc)) { 5596 LOG_CLI((BSL_META_U(unit, 5597 " %s: type=%s, speed=%d, forced cl72=%d, " 5598 "mode(1.%04x)=%04x\n" 5599 " pmdtype(1.%04x)=%04x, " 5600 "lb(1.%04x)=%04x, txdis(1.%04x)=%04x/(1.%04x)=%04x\n" 5601 " link(1.%04x) : " 5602 "(ln0=%04x, ln1=%04x, ln2=%04x, ln3=%04x)\n" 5603 " pol(1.%04x) : " 5604 "(ln0=%04x, ln1=%04x, ln2=%04x, ln3=%04x)\n"), 5605 (side == PHY84328_INTF_SIDE_LINE) ? 5606 "Line " : "System ", 5607 phy84328_intf_names[intf->type], 5608 intf->speed, SYS_FORCED_CL72(pc), 5609 PHY84328_DEV1_PMD_CONTROL_REGISTER, data1, 5610 PHY84328_DEV1_PMD_CONTROL_2_REGISTER, data2, 5611 PHY84328_SYS_DEV1_ANATXACONTROL6, data3, 5612 PHY84328_DEV1_ANATXACONTROL2, data4, 5613 PHY84328_DEV1_ANATXACONTROL6, data5, 5614 PHY84328_DEV1_ANARXSTATUS, link_sts[0], 5615 link_sts[1], link_sts[2], link_sts[3], 5616 CUR_DATAPATH(pc) == PHY84328_DATAPATH_20 ? 5617 PHY84328_DEV1_ANATXACONTROL : 5618 PHY84328_DEV1_ANATXACONTROL4, 5619 pol_sts[0], pol_sts[1], pol_sts[2], pol_sts[3])); 5620 5621 if (side == PHY84328_INTF_SIDE_LINE) { 5622 LOG_CLI((BSL_META_U(unit, 5623 " pol_inv(1.%04x) : " 5624 "(ln0=%04x, ln1=%04x, ln2=%04x, ln3=%04x)\n"), 5625 PHY84328_DEV1_GP_REGISTER_RX_INV, 5626 pol_inv_sts[0], pol_inv_sts[1], 5627 pol_inv_sts[2], pol_inv_sts[3])); 5628 } 5629 LOG_CLI((BSL_META_U(unit, 5630 " txdrv(1.%04x) : " 5631 "(ln0=%04x, ln1=%04x, ln2=%04x, ln3=%04x)\n" 5632 " preman(1.%04x) : " 5633 "(ln0=%04x, ln1=%04x, ln2=%04x, ln3=%04x)\n" 5634 " premain(1.%04x) : " 5635 "(ln0=%04x, ln1=%04x, ln2=%04x, ln3=%04x)\n" 5636 " preprepos(1.%04x) : " 5637 "(ln0=%04x, ln1=%04x, ln2=%04x, ln3=%04x)\n"), 5638 PHY84328_DEV1_ANATXACONTROL1, tx_drv[0], 5639 tx_drv[1], tx_drv[2], tx_drv[3], 5640 PHY84328_SYS_DEV1_XFI_AFE_CTL2, preemph_manual[0], 5641 preemph_manual[1], preemph_manual[2], preemph_manual[3], 5642 PHY84328_DEV1_ANATXACONTROL2, preemph_main[0], 5643 preemph_main[1], preemph_main[2], preemph_main[3], 5644 PHY84328_DEV1_ANATXACONTROL3, preemph_pre_post[0], 5645 preemph_pre_post[1], preemph_pre_post[2], 5646 preemph_pre_post[3])); 5647 } else { 5648 LOG_CLI((BSL_META_U(unit, 5649 "Lane:%d: %s: type=%s, speed=%d, " 5650 "forced cl72=%d, mode(1.%04x)=%04x\n" 5651 " pmdtype(1.%04x)=%04x, " 5652 "lb(1.%04x)=%04x, txdis(1.%04x)=%04x/(1.%04x)=%04x\n" 5653 " link(1.%04x)=%04x, " 5654 "txdrv(1.%04x)=%04x, pol(1.%04x)=%04x"), 5655 i, (side == PHY84328_INTF_SIDE_LINE) ? 5656 "Line " : "System ", 5657 phy84328_intf_names[intf->type], 5658 intf->speed, SYS_FORCED_CL72(pc), 5659 PHY84328_DEV1_PMD_CONTROL_REGISTER, data1, 5660 PHY84328_DEV1_PMD_CONTROL_2_REGISTER, data2, 5661 PHY84328_SYS_DEV1_ANATXACONTROL6, data3, 5662 PHY84328_DEV1_ANATXACONTROL2, data4, 5663 PHY84328_DEV1_ANATXACONTROL6, data5, 5664 PHY84328_DEV1_ANARXSTATUS, link_sts[i], 5665 PHY84328_DEV1_ANATXACONTROL1, tx_drv[i], 5666 CUR_DATAPATH(pc) == PHY84328_DATAPATH_20 ? 5667 PHY84328_DEV1_ANATXACONTROL : 5668 PHY84328_DEV1_ANATXACONTROL4, 5669 pol_sts[i])); 5670 if (side == PHY84328_INTF_SIDE_LINE) { 5671 LOG_CLI((BSL_META_U(unit, 5672 ", pol_inv(1.%04x)=%04x"), 5673 PHY84328_DEV1_GP_REGISTER_RX_INV, 5674 pol_inv_sts[i])); 5675 } 5676 LOG_CLI((BSL_META_U(unit, 5677 "\n" 5678 " preman(1.%04x)=%04x," 5679 "premain(1.%04x)=%04x, preprepos(1.%04x)=%04x\n"), 5680 PHY84328_SYS_DEV1_XFI_AFE_CTL2, preemph_manual[i], 5681 PHY84328_DEV1_ANATXACONTROL2, preemph_main[i], 5682 PHY84328_DEV1_ANATXACONTROL3, preemph_pre_post[i])); 5683 } 5684 } 5685 5686 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 5687 5688 if (int_pc) { 5689 int lb; 5690 SOC_IF_ERROR_RETURN(PHY_INTERFACE_GET(int_pc->pd, unit, port, &iif)); 5691 SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, &ilink)); 5692 SOC_IF_ERROR_RETURN(_phy_84328_lb_get(unit, port, &lb)); 5693 if (lb) { 5694 /* Clear the sticky bit if in loopback */ 5695 SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, &ilink)); 5696 } 5697 SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, &ispeed)); 5698 SOC_IF_ERROR_RETURN(PHY_AUTO_NEGOTIATE_GET(int_pc->pd, unit, port, &ian, &ian_done)); 5699 LOG_CLI((BSL_META_U(unit, 5700 " Internal: type=%s, speed=%d, link=%d, an=%d\n===\n"), 5701 phy84328_intf_names[iif], ispeed, ilink, ian)); 5702 } 5703 if (saved_side == PHY84328_INTF_SIDE_SYS) { 5704 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 5705 } 5706 5707 return SOC_E_NONE; 5708 } 5709 5710 STATIC int 5711 _phy_84328_control_driver_supply_set(int unit, soc_port_t port, phy84328_intf_side_t side, 5712 uint32 value) 5713 { 5714 soc_port_phy_control_driver_supply_t ds; 5715 uint16 tx_mode = 0; 5716 5717 ds = (soc_port_phy_control_driver_supply_t) value; 5718 switch (ds) { 5719 case SOC_PHY_CONTROL_DRIVER_SUPPLY_1_5V_1_0V: 5720 tx_mode = 4; 5721 break; 5722 case SOC_PHY_CONTROL_DRIVER_SUPPLY_1_0V_700MV: 5723 tx_mode = 0; 5724 break; 5725 case SOC_PHY_CONTROL_DRIVER_SUPPLY_1_5V_700MV: 5726 tx_mode = 1; 5727 break; 5728 default: 5729 return SOC_E_PARAM; 5730 } 5731 5732 return _phy_84328_tx_mode_set(unit, port, side, tx_mode); 5733 } 5734 5735 STATIC int 5736 _phy_84328_control_driver_supply_get(int unit, soc_port_t port, phy84328_intf_side_t side, 5737 uint32 *value) 5738 { 5739 uint16 tx_mode = 0; 5740 soc_port_phy_control_driver_supply_t ds; 5741 5742 SOC_IF_ERROR_RETURN(_phy_84328_tx_mode_get(unit, port, side, &tx_mode)); 5743 5744 switch (tx_mode) { 5745 case 4: 5746 ds = SOC_PHY_CONTROL_DRIVER_SUPPLY_1_5V_1_0V; 5747 break; 5748 case 0: 5749 ds = SOC_PHY_CONTROL_DRIVER_SUPPLY_1_0V_700MV; 5750 break; 5751 case 1: 5752 ds = SOC_PHY_CONTROL_DRIVER_SUPPLY_1_5V_700MV; 5753 break; 5754 default: 5755 /* The value is not reliable */ 5756 *value = 0; 5757 return SOC_E_UNAVAIL; 5758 } 5759 5760 *value = (uint32) ds; 5761 return SOC_E_NONE; 5762 } 5763 5764 STATIC int 5765 _phy_84328_sw_rx_los_control_set(int unit, soc_port_t port, uint32 value) 5766 { 5767 phy_ctrl_t *pc= EXT_PHY_SW_STATE(unit, port); 5768 phy84328_sw_rx_los_t *sw_rx_los = &(SW_RX_LOS(pc)); 5769 5770 #ifdef BCM_WARM_BOOT_SUPPORT 5771 if ( SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit) ) { 5772 return SOC_E_NONE; 5773 } 5774 /* preserve SW RxLOS status in register 1.0xC01A for warmboot support */ 5775 SOC_IF_ERROR_RETURN( _phy_84328_preserve_sw_rx_los(unit, port, value) ); 5776 #endif 5777 5778 sw_rx_los->cfg_enable = value; 5779 sw_rx_los->cur_enable = value; 5780 if (value) { 5781 sw_rx_los->sys_link = 0; 5782 sw_rx_los->state = PHY84328_SW_RX_LOS_RESET; 5783 sw_rx_los->link_status = 0; 5784 sw_rx_los->link_no_pcs = 0; 5785 sw_rx_los->restarts = 0; 5786 #ifdef SW_RX_LOS_FLAP_CHECK 5787 sw_rx_los->fault_report_dis = 0; 5788 if (sw_rx_los->macd == NULL) { 5789 SOC_IF_ERROR_RETURN(soc_mac_probe(unit, port, &(sw_rx_los->macd))); 5790 } 5791 #endif 5792 } 5793 return SOC_E_NONE; 5794 } 5795 5796 STATIC int 5797 _phy_84328_fw_rx_los_control_set(int unit, soc_port_t port, uint32 value) 5798 { 5799 int lane_start, lane_end, lane; 5800 int fw_rx_los_en_data, fw_rx_los_en_mask; 5801 phy_ctrl_t *pc= EXT_PHY_SW_STATE(unit, port); 5802 uint32 lane_reg[PHY84328_NUM_LANES] = /* per lane registers timeout */ 5803 { 0xca99, 0xca9b, 0xca9d, 0xca9f }; 5804 5805 FW_RX_LOS(pc) = value; 5806 5807 fw_rx_los_en_mask = (1 << 15) | (1 << 14); 5808 if (value) { 5809 if (PHY84328_SINGLE_PORT_MODE(pc)) { 5810 lane_start = 0; 5811 lane_end = PHY84328_NUM_LANES; 5812 } 5813 else { 5814 lane_start = pc->phy_id & 0x3; 5815 lane_end = lane_start + 1; 5816 } 5817 for (lane = lane_start; lane < lane_end; lane++) { 5818 /* Program the timeout value */ 5819 SOC_IF_ERROR_RETURN( 5820 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, lane_reg[lane], 5821 0xffff, 0xffff)); 5822 } 5823 fw_rx_los_en_data = (1 << 15) | (1 << 14); 5824 } else { 5825 fw_rx_los_en_data = 0; 5826 } 5827 SOC_IF_ERROR_RETURN( 5828 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 0xc480, fw_rx_los_en_data, 5829 fw_rx_los_en_mask)); 5830 if (value){ 5831 /* Update interface type/speed */ 5832 SOC_IF_ERROR_RETURN(_phy_84328_intf_line_sys_update(unit, port)); 5833 } 5834 5835 return SOC_E_NONE; 5836 } 5837 5838 STATIC int 5839 _phy_84328_rx_los_control_set(int unit, soc_port_t port, uint32 value) 5840 { 5841 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5842 int rv = SOC_E_NONE; 5843 int rv2 = SOC_E_NONE; 5844 5845 switch (value) { 5846 case SOC_PHY_CONTROL_RX_LOS_NONE: 5847 rv = _phy_84328_sw_rx_los_control_set(unit, port, 0); 5848 rv2 = _phy_84328_fw_rx_los_control_set(unit, port, 0); 5849 rv = (rv == SOC_E_NONE) ? rv2 : rv; 5850 break; 5851 case SOC_PHY_CONTROL_RX_LOS_FIRMWARE: 5852 if (DEVREV(pc) == 0x00a0) { 5853 rv = _phy_84328_sw_rx_los_control_set(unit, port, 1); 5854 } else { 5855 rv = _phy_84328_sw_rx_los_control_set(unit, port, 0); 5856 rv2 = _phy_84328_fw_rx_los_control_set(unit, port, 1); 5857 rv = (rv == SOC_E_NONE) ? rv2 : rv; 5858 } 5859 break; 5860 case SOC_PHY_CONTROL_RX_LOS_SOFTWARE: 5861 default: 5862 if (DEVREV(pc) == 0x00a0) { 5863 rv = _phy_84328_sw_rx_los_control_set(unit, port, 1); 5864 } else { 5865 rv = _phy_84328_fw_rx_los_control_set(unit, port, 0); 5866 rv2 = _phy_84328_sw_rx_los_control_set(unit, port, 1); 5867 rv = (rv == SOC_E_NONE) ? rv2 : rv; 5868 } 5869 break; 5870 } 5871 5872 return rv; 5873 } 5874 5875 STATIC int 5876 _phy_84328_rx_los_control_get(int unit, soc_port_t port, uint32 *value) 5877 { 5878 phy84328_sw_rx_los_t *sw_rx_los; 5879 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 5880 5881 sw_rx_los = &(SW_RX_LOS(pc)); 5882 5883 if (sw_rx_los->cur_enable) { 5884 *value = SOC_PHY_CONTROL_RX_LOS_SOFTWARE; 5885 } else if (FW_RX_LOS(pc)) { 5886 *value = SOC_PHY_CONTROL_RX_LOS_FIRMWARE; 5887 } else { 5888 *value = SOC_PHY_CONTROL_RX_LOS_NONE; 5889 } 5890 5891 return SOC_E_NONE; 5892 } 5893 5894 STATIC int 5895 _phy_84328_mod_auto_detect_set(int unit, soc_port_t port, uint32 value) 5896 { 5897 phy_ctrl_t *pc; 5898 uint16 data; 5899 uint16 rddata; 5900 uint16 count = 0; 5901 uint16 mask; 5902 5903 pc = EXT_PHY_SW_STATE(unit, port); 5904 mask = PHY84328_DEV1_GP_REG_0_ENABLE_SFP_MOD_DETECT_MASK; 5905 data = value ? mask : 0; 5906 5907 SOC_IF_ERROR_RETURN( 5908 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, data, 5909 mask)); 5910 5911 if (!value) { 5912 /* Request is disabling mod auto detect, need to wait until I2CM FSM becomes IDLE */ 5913 /* Wait approx for 325 ms */ 5914 while (count < I2CM_IDLE_WAIT_COUNT){ 5915 SOC_IF_ERROR_RETURN( 5916 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_I2C_CONTROL_REGISTER, &rddata)); 5917 if ((rddata & 0xC) == 0) { 5918 break; 5919 } 5920 count ++; 5921 sal_usleep(I2CM_IDLE_WAIT_CHUNK * 1000); 5922 } 5923 if (count >= I2CM_IDLE_WAIT_COUNT) { 5924 return SOC_E_BUSY; 5925 } 5926 } 5927 5928 /* Update the global database */ 5929 MOD_AUTO_DETECT(pc) = value ? 1:0; 5930 5931 return SOC_E_NONE; 5932 } 5933 5934 STATIC int 5935 _phy_84328_mod_auto_detect_get(int unit, soc_port_t port, uint32 *value) 5936 { 5937 phy_ctrl_t *pc; 5938 uint16 data; 5939 5940 pc = EXT_PHY_SW_STATE(unit, port); 5941 5942 SOC_IF_ERROR_RETURN( 5943 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REG_0, &data)); 5944 5945 if( data & PHY84328_DEV1_GP_REG_0_ENABLE_SFP_MOD_DETECT_MASK ) { 5946 *value = 1; 5947 } else { 5948 *value = 0; 5949 } 5950 return SOC_E_NONE; 5951 } 5952 5953 STATIC int 5954 _phy_84328_force_cl72_config(int unit, soc_port_t port, uint32 enable) 5955 { 5956 uint16 intf_side = 0; 5957 uint16 data = 0 , mask = 0; 5958 phy_ctrl_t *pc; /* PHY software state */ 5959 pc = EXT_PHY_SW_STATE(unit, port); 5960 5961 intf_side = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 5962 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE; 5963 if (intf_side == PHY84328_INTF_SIDE_SYS) { 5964 data = enable ? PHY84328_DEV1_GP_REGISTER_1_SYSTEM_FORCED_CL72_MODE_MASK : 0; 5965 mask = PHY84328_DEV1_GP_REGISTER_1_SYSTEM_FORCED_CL72_MODE_MASK; 5966 } else { 5967 data = enable ? PHY84328_DEV1_GP_REGISTER_1_LINE_FORCED_CL72_MODE_MASK : 0; 5968 mask = PHY84328_DEV1_GP_REGISTER_1_LINE_FORCED_CL72_MODE_MASK; 5969 } 5970 data |= PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK; 5971 mask |= PHY84328_DEV1_GP_REGISTER_1_FINISH_CHANGE_MASK; 5972 SOC_IF_ERROR_RETURN( 5973 _phy_84328_intf_update(unit, port, data, mask)); 5974 return SOC_E_NONE; 5975 } 5976 5977 STATIC int 5978 _phy_84328_force_cl72_status(int unit, soc_port_t port, uint32 *value) 5979 { 5980 uint16 intf_side = 0, data = 0; 5981 phy_ctrl_t *pc; /* PHY software state */ 5982 pc = EXT_PHY_SW_STATE(unit, port); 5983 5984 intf_side = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 5985 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE; 5986 5987 SOC_IF_ERROR_RETURN( 5988 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GP_REGISTER_3, &data)); 5989 *value = 0; 5990 5991 if (intf_side == PHY84328_INTF_SIDE_SYS) { 5992 *value = (data & PHY84328_DEV1_GP_REGISTER_1_SYSTEM_FORCED_CL72_MODE_MASK) ? 1 : 0; 5993 } else { 5994 *value = (data & PHY84328_DEV1_GP_REGISTER_1_LINE_FORCED_CL72_MODE_MASK) ? 1 : 0; 5995 } 5996 5997 return SOC_E_NONE; 5998 } 5999 6000 /* 6001 * Function: 6002 * _phy_84328_control_set 6003 * Purpose: 6004 * Configure PHY device specific control fucntion. 6005 * Parameters: 6006 * unit - StrataSwitch unit #. 6007 * port - StrataSwitch port #. 6008 * type - Control to update 6009 * value - New setting for the control 6010 * Returns: 6011 * SOC_E_NONE 6012 */ 6013 STATIC int 6014 _phy_84328_control_set(int unit, soc_port_t port, int intf, int lane, 6015 soc_phy_control_t type, uint32 value) 6016 { 6017 phy_ctrl_t *pc; /* PHY software state */ 6018 int rv; 6019 6020 pc = EXT_PHY_SW_STATE(unit, port); 6021 6022 PHY_CONTROL_TYPE_CHECK(type); 6023 6024 rv = SOC_E_UNAVAIL; 6025 if (intf == PHY_DIAG_INTF_SYS) { 6026 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 6027 pc->flags |= PHYCTRL_SYS_SIDE_CTRL ; 6028 } 6029 switch (type) { 6030 case SOC_PHY_CONTROL_PREEMPHASIS: 6031 /* fall through */ 6032 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 6033 /* fall through */ 6034 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 6035 /* fall through */ 6036 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 6037 /* fall through */ 6038 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 6039 rv = _phy_84328_control_preemphasis_set(unit, port, type, 6040 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6041 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6042 value); 6043 break; 6044 case SOC_PHY_CONTROL_DRIVER_CURRENT: 6045 /* fall through */ 6046 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 6047 /* fall through */ 6048 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 6049 /* fall through */ 6050 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 6051 /* fall through */ 6052 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 6053 /* fall through */ 6054 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 6055 /* fall through */ 6056 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 6057 /* fall through */ 6058 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 6059 /* fall through */ 6060 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 6061 /* fall through */ 6062 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 6063 rv = _phy_84328_control_tx_driver_set(unit, port, type, 6064 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6065 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6066 value); 6067 break; 6068 case SOC_PHY_CONTROL_EDC_MODE: 6069 rv = _phy_84328_control_edc_mode_set(unit,port,value); 6070 break; 6071 case SOC_PHY_CONTROL_CLOCK_ENABLE: 6072 rv = _phy_84328_control_recovery_clock_set(unit,port,value); 6073 break; 6074 case SOC_PHY_CONTROL_CLOCK_FREQUENCY: 6075 rv = _phy_84328_control_recovery_clock_freq_set(unit,port,value); 6076 break; 6077 case SOC_PHY_CONTROL_PRBS_POLYNOMIAL: 6078 rv = _phy_84328_control_prbs_polynomial_set(unit, port, value, TRUE); 6079 if (SOC_SUCCESS(rv)) { 6080 rv = _phy_84328_control_prbs_polynomial_set(unit, port,value, FALSE); 6081 } 6082 break; 6083 case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA: 6084 rv = _phy_84328_control_prbs_tx_invert_data_set(unit, port, value); 6085 if (SOC_SUCCESS(rv)) { 6086 rv = _phy_84328_control_prbs_rx_invert_data_set(unit, port, value); 6087 } 6088 break; 6089 case SOC_PHY_CONTROL_PRBS_TX_ENABLE: 6090 /* fall through */ 6091 case SOC_PHY_CONTROL_PRBS_RX_ENABLE: 6092 /* tx/rx is enabled at the same time. no seperate control */ 6093 rv = _phy_84328_control_prbs_enable_set(unit, port, value); 6094 break; 6095 case SOC_PHY_CONTROL_LOOPBACK_REMOTE: 6096 rv = _phy_84328_remote_loopback_set(unit, port, intf, value); 6097 break; 6098 case SOC_PHY_CONTROL_PORT_PRIMARY: 6099 rv = soc_phyctrl_primary_set(unit, port, (soc_port_t)value); 6100 break; 6101 case SOC_PHY_CONTROL_PORT_OFFSET: 6102 rv = soc_phyctrl_offset_set(unit, port, (int)value); 6103 break; 6104 case SOC_PHY_CONTROL_SOFTWARE_RX_LOS: 6105 rv = _phy_84328_rx_los_control_set(unit, port, value); 6106 break; 6107 case SOC_PHY_CONTROL_DUMP: 6108 /* in control set for consistency with other drivers */ 6109 rv = _phy_84328_debug_info(unit, port); 6110 break; 6111 case SOC_PHY_CONTROL_DRIVER_SUPPLY: 6112 rv = _phy_84328_control_driver_supply_set(unit, port, 6113 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6114 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6115 value); 6116 break; 6117 case SOC_PHY_CONTROL_RX_SEQ_TOGGLE: 6118 /* value is not used since this is always a toggle ->1->0 */ 6119 rv = _phy_84328_do_rxseq_restart(unit, port, 6120 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6121 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE); 6122 break; 6123 case SOC_PHY_CONTROL_MOD_AUTO_DETECT_ENABLE: 6124 rv = _phy_84328_mod_auto_detect_set(unit,port,value); 6125 break; 6126 case SOC_PHY_CONTROL_CL72: 6127 rv = _phy_84328_force_cl72_config(unit, port, value); 6128 break; 6129 case SOC_PHY_CONTROL_PCS_MODE: 6130 { 6131 phy_ctrl_t *int_pc; 6132 phy84328_intf_cfg_t *line_intf; 6133 rv = SOC_E_NONE; 6134 int_pc = INT_PHY_SW_STATE(unit, port); 6135 line_intf = &(LINE_INTF(pc)); 6136 if (int_pc) { 6137 SOC_IF_ERROR_RETURN( 6138 PHY_CONTROL_SET(int_pc->pd, unit, port, type, value)); 6139 6140 SOC_IF_ERROR_RETURN(PHY_SPEED_SET(int_pc->pd, unit, port, 6141 line_intf->speed)); 6142 } else { 6143 rv = SOC_E_INTERNAL; 6144 } 6145 } 6146 break; 6147 default: 6148 rv = SOC_E_UNAVAIL; 6149 break; 6150 } 6151 if (intf == PHY_DIAG_INTF_SYS) { 6152 /* if it is targeted to the system side, switch back */ 6153 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 6154 pc->flags &= ~PHYCTRL_SYS_SIDE_CTRL ; 6155 } 6156 return rv; 6157 } 6158 6159 STATIC int 6160 phy_84328_control_port_set(int unit, soc_port_t port, 6161 soc_phy_control_t type, uint32 value) 6162 { 6163 SOC_IF_ERROR_RETURN(_phy_84328_control_set(unit, port, PHY_DIAG_INTF_LINE, 6164 PHY_DIAG_LN_DFLT, type, value)); 6165 return SOC_E_NONE; 6166 } 6167 6168 /* 6169 * Function: 6170 * phy_84328_control_get 6171 * Purpose: 6172 * Get current control settign of the PHY. 6173 * Parameters: 6174 * unit - StrataSwitch unit #. 6175 * port - StrataSwitch port #. 6176 * type - Control to update 6177 * value - (OUT)Current setting for the control 6178 * Returns: 6179 * SOC_E_NONE 6180 */ 6181 STATIC int 6182 _phy_84328_control_get(int unit, soc_port_t port, int intf, int lane, 6183 soc_phy_control_t type, uint32 *value) 6184 { 6185 phy_ctrl_t *pc; /* PHY software state */ 6186 int rv, offset; 6187 soc_port_t primary; 6188 pc = EXT_PHY_SW_STATE(unit, port); 6189 6190 6191 PHY_CONTROL_TYPE_CHECK(type); 6192 6193 if (intf == PHY_DIAG_INTF_SYS) { 6194 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 6195 pc->flags |= PHYCTRL_SYS_SIDE_CTRL ; 6196 } 6197 rv = SOC_E_UNAVAIL; 6198 switch(type) { 6199 case SOC_PHY_CONTROL_PREEMPHASIS: 6200 /* fall through */ 6201 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 6202 /* fall through */ 6203 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 6204 /* fall through */ 6205 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 6206 /* fall through */ 6207 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 6208 rv = _phy_84328_control_preemphasis_get(unit, port, type, 6209 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6210 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6211 value); 6212 break; 6213 case SOC_PHY_CONTROL_DRIVER_CURRENT: 6214 /* fall through */ 6215 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 6216 /* fall through */ 6217 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 6218 /* fall through */ 6219 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 6220 /* fall through */ 6221 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 6222 /* fall through */ 6223 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 6224 /* fall through */ 6225 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE0: 6226 /* fall through */ 6227 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE1: 6228 /* fall through */ 6229 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE2: 6230 /* fall through */ 6231 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT_LANE3: 6232 rv = _phy_84328_control_tx_driver_get(unit, port, type, 6233 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6234 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6235 value); 6236 break; 6237 case SOC_PHY_CONTROL_EDC_MODE: 6238 rv = _phy_84328_control_edc_mode_get(unit,port,value); 6239 break; 6240 case SOC_PHY_CONTROL_CLOCK_ENABLE: 6241 rv = SOC_E_NONE; 6242 break; 6243 case SOC_PHY_CONTROL_PRBS_POLYNOMIAL: 6244 rv = _phy_84328_control_prbs_polynomial_get(unit, port, value); 6245 break; 6246 case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA: 6247 rv = _phy_84328_control_prbs_tx_invert_data_get(unit, port, value); 6248 break; 6249 case SOC_PHY_CONTROL_PRBS_TX_ENABLE: 6250 /* fall through */ 6251 case SOC_PHY_CONTROL_PRBS_RX_ENABLE: 6252 rv = _phy_84328_control_prbs_enable_get(unit, port, value); 6253 break; 6254 case SOC_PHY_CONTROL_PRBS_RX_STATUS: 6255 rv = _phy_84328_control_prbs_rx_status_get(unit, port, 6256 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6257 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6258 value); 6259 break; 6260 case SOC_PHY_CONTROL_CLOCK_FREQUENCY: 6261 break; 6262 case SOC_PHY_CONTROL_PORT_PRIMARY: 6263 SOC_IF_ERROR_RETURN 6264 (soc_phyctrl_primary_get(unit, port, &primary)); 6265 *value = (uint32) primary; 6266 rv = SOC_E_NONE; 6267 break; 6268 case SOC_PHY_CONTROL_PORT_OFFSET: 6269 SOC_IF_ERROR_RETURN 6270 (soc_phyctrl_offset_get(unit, port, &offset)); 6271 *value = (uint32) offset; 6272 rv = SOC_E_NONE; 6273 break; 6274 case SOC_PHY_CONTROL_LOOPBACK_REMOTE: 6275 rv = _phy_84328_remote_loopback_get(unit, port, intf, value); 6276 break; 6277 case SOC_PHY_CONTROL_SOFTWARE_RX_LOS: 6278 rv = _phy_84328_rx_los_control_get(unit, port, value); 6279 break; 6280 case SOC_PHY_CONTROL_DUMP: 6281 *value = 0; 6282 rv = SOC_E_NONE; 6283 break; 6284 case SOC_PHY_CONTROL_DRIVER_SUPPLY: 6285 rv = _phy_84328_control_driver_supply_get(unit, port, 6286 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6287 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6288 value); 6289 break; 6290 case SOC_PHY_CONTROL_RX_SEQ_DONE: 6291 rv = _phy_84328_rx_seq_done_get(unit, port, 6292 (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 6293 PHY84328_INTF_SIDE_SYS : PHY84328_INTF_SIDE_LINE, 6294 value); 6295 break; 6296 case SOC_PHY_CONTROL_MOD_AUTO_DETECT_ENABLE: 6297 rv = _phy_84328_mod_auto_detect_get(unit, port, value); 6298 break; 6299 case SOC_PHY_CONTROL_CL72_STATUS: 6300 rv = _phy_84328_force_cl72_status(unit, port, value); 6301 break; 6302 case SOC_PHY_CONTROL_PCS_MODE: 6303 { 6304 phy_ctrl_t *int_pc; 6305 int_pc = INT_PHY_SW_STATE(unit, port); 6306 if (int_pc) { 6307 rv = PHY_CONTROL_GET(int_pc->pd, unit, port, type, value); 6308 } else { 6309 rv = SOC_E_INTERNAL; 6310 } 6311 } 6312 break; 6313 6314 default: 6315 rv = SOC_E_UNAVAIL; 6316 break; 6317 } 6318 6319 if (intf == PHY_DIAG_INTF_SYS) { 6320 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 6321 pc->flags &= ~PHYCTRL_SYS_SIDE_CTRL ; 6322 } 6323 return rv; 6324 } 6325 STATIC int 6326 phy_84328_control_port_get(int unit, soc_port_t port, 6327 soc_phy_control_t type, uint32 *value) 6328 { 6329 int intf; 6330 6331 intf = PHY_DIAG_INTF_LINE; 6332 SOC_IF_ERROR_RETURN 6333 (_phy_84328_control_get(unit, port, intf, PHY_DIAG_LN_DFLT, type, value)); 6334 6335 return SOC_E_NONE; 6336 } 6337 6338 /* Returns whether interface has cl72 */ 6339 STATIC int 6340 _phy_84328_cl72_en(int unit, soc_port_t port, phy84328_intf_side_t side) 6341 { 6342 int cl72 = FALSE; 6343 phy_ctrl_t *pc; 6344 phy84328_intf_cfg_t *ifc; 6345 6346 pc = EXT_PHY_SW_STATE(unit, port); 6347 ifc = (side == PHY84328_INTF_SIDE_LINE) ? &(LINE_INTF(pc)) : &(SYS_INTF(pc)); 6348 switch (ifc->type) { 6349 case SOC_PORT_IF_KR: 6350 case SOC_PORT_IF_KR4: 6351 cl72 = TRUE; 6352 break; 6353 case SOC_PORT_IF_CR4: 6354 /* System side is always DAC */ 6355 if (side == PHY84328_INTF_SIDE_SYS) { 6356 cl72 = FALSE; 6357 } else { 6358 /* If no AN, it's really DAC */ 6359 cl72 = AN_EN(pc); 6360 } 6361 break; 6362 default: 6363 cl72 = FALSE; 6364 break; 6365 } 6366 return cl72; 6367 } 6368 6369 /* dsc values */ 6370 struct phy84328_dsc_cb { 6371 int tx_pre_cursor; 6372 int tx_main; 6373 int tx_post_cursor; 6374 char *vga_bias_reduced; 6375 int postc_metric; 6376 int pf_ctrl; 6377 int vga_sum; 6378 int dfe1_bin; 6379 int dfe2_bin; 6380 int dfe3_bin; 6381 int dfe4_bin; 6382 int dfe5_bin; 6383 int integ_reg; 6384 int integ_reg_xfer; 6385 int clk90_offset; 6386 int slicer_target; 6387 int offset_pe; 6388 int offset_ze; 6389 int offset_me; 6390 int offset_po; 6391 int offset_zo; 6392 int offset_mo; 6393 }; 6394 6395 STATIC int 6396 _phy_84328_diag_dsc(int unit, soc_port_t port, int intf, int lane) 6397 { 6398 int i, reg, lanes, regval; 6399 uint16 data16; 6400 phy_ctrl_t *pc; 6401 phy84328_intf_side_t side; 6402 struct phy84328_dsc_cb *dsc_cbp; 6403 struct phy84328_dsc_cb dsc_cb[PHY84328_NUM_LANES]; 6404 6405 pc = EXT_PHY_SW_STATE(unit, port); 6406 6407 if (PHY84328_SINGLE_PORT_MODE(pc)) { 6408 lanes = PHY84328_NUM_LANES ; 6409 } 6410 else { 6411 lanes = 1; 6412 } 6413 side = (intf == PHY_DIAG_INTF_LINE) ? PHY84328_INTF_SIDE_LINE : 6414 PHY84328_INTF_SIDE_SYS; 6415 sal_memset((char *)&dsc_cb[0], 0, (sizeof(dsc_cb))); 6416 6417 PHY_84328_MICRO_PAUSE(unit, port, "dsc"); 6418 _phy_84328_intf_side_regs_select(unit, port, side); 6419 for (i = 0; i < lanes; i++) { 6420 if (PHY84328_SINGLE_PORT_MODE(pc)) { 6421 /* Select the lane and side to access */ 6422 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, i)); 6423 } 6424 dsc_cbp = &(dsc_cb[i]); 6425 6426 /* tx drive pre, main, post cursor taps are read differently for cl72 */ 6427 if (_phy_84328_cl72_en(unit, port, side)) { 6428 uint16 saved_reg; 6429 6430 /* 1.c063[15:14]=1 to get port cl72 tap values in 1.c060 */ 6431 reg = 0xc063; 6432 SOC_IF_ERROR_RETURN 6433 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6434 saved_reg = data16; 6435 regval = 0x4000 | (data16 & 0x3fff); 6436 SOC_IF_ERROR_RETURN 6437 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, data16)); 6438 reg = 0xc060; 6439 SOC_IF_ERROR_RETURN 6440 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6441 6442 /* tx_pre_cursor */ 6443 regval = data16 & 0xf; 6444 dsc_cbp->tx_pre_cursor = regval; 6445 6446 /* tx_post_cursor */ 6447 regval = (data16 >> 10) & 0x1f; 6448 dsc_cbp->tx_post_cursor = regval; 6449 6450 /* tx_main */ 6451 regval = (data16 >> 4) & 0x3f; 6452 dsc_cbp->tx_main = regval; 6453 6454 /* Restore 1.c063 to original values used to access 1.c060 */ 6455 SOC_IF_ERROR_RETURN 6456 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, saved_reg)); 6457 } else { 6458 reg = 0xc067; 6459 SOC_IF_ERROR_RETURN 6460 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6461 6462 /* tx_pre_cursor */ 6463 regval = data16 & 0x7; 6464 dsc_cbp->tx_pre_cursor = regval; 6465 6466 /* tx_post_cursor */ 6467 regval = (data16 >> 4) & 0x1F; 6468 dsc_cbp->tx_post_cursor = regval; 6469 6470 /* tx_main */ 6471 reg = 0xc066; 6472 SOC_IF_ERROR_RETURN 6473 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6474 regval = (data16 >> 11) & 0x1F; 6475 dsc_cbp->tx_main = regval; 6476 } 6477 6478 /* vga_bias_reduced */ 6479 reg = 0xc0BD; 6480 SOC_IF_ERROR_RETURN 6481 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6482 regval = data16 & (1 << 4); 6483 if (regval) { 6484 dsc_cbp->vga_bias_reduced = "88%"; 6485 } else { 6486 dsc_cbp->vga_bias_reduced = "100%"; 6487 } 6488 6489 /* post2 tap - c068[10:8] */ 6490 reg = 0xc068; 6491 SOC_IF_ERROR_RETURN 6492 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6493 regval = (data16 >> 8) & 0x7; 6494 dsc_cbp->postc_metric = regval; 6495 6496 6497 /* pf DSC_3_ADDR=0xc220 + 11 */ 6498 reg = 0xc220 + 11; 6499 SOC_IF_ERROR_RETURN 6500 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6501 regval = (data16 & 0xf); 6502 dsc_cbp->pf_ctrl = regval; 6503 6504 /* vga sum DSC_3_ADDR=0xc220 + 5 */ 6505 reg = 0xc220 + 5; 6506 SOC_IF_ERROR_RETURN 6507 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6508 regval = (data16 & 63); 6509 dsc_cbp->vga_sum = regval; 6510 6511 /* dfe1_bin DSC_3_ADDR=0xc220 + 5 */ 6512 reg = 0xc220 + 5; 6513 SOC_IF_ERROR_RETURN 6514 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6515 regval = data16; 6516 regval /= 64; 6517 regval &= 63; 6518 dsc_cbp->dfe1_bin = regval; 6519 6520 /* dfe2_bin DSC_3_ADDR=0xc220 + 6 */ 6521 reg = 0xc220 + 6; 6522 SOC_IF_ERROR_RETURN 6523 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6524 regval = data16; 6525 regval &= 63; 6526 if (regval >= 32) { 6527 regval -=64; 6528 } 6529 dsc_cbp->dfe2_bin = regval; 6530 6531 /* dfe3_bin DSC_3_ADDR=0xc220 + 6 */ 6532 reg = 0xc220 + 6; 6533 SOC_IF_ERROR_RETURN 6534 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6535 regval = data16; 6536 regval /= 64; 6537 regval &= 63; 6538 if (regval >= 32) { 6539 regval -=64; 6540 } 6541 dsc_cbp->dfe3_bin = regval; 6542 6543 /* dfe4_bin DSC_3_ADDR=0xc220 + 7 */ 6544 reg = 0xc220 + 7; 6545 SOC_IF_ERROR_RETURN 6546 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6547 regval = data16; 6548 regval &= 31; 6549 if (regval >= 16) { 6550 regval -=32; 6551 } 6552 dsc_cbp->dfe4_bin = regval; 6553 6554 /* dfe5_bin DSC_3_ADDR=0xc220 + 7 */ 6555 reg = 0xc220 + 7; 6556 SOC_IF_ERROR_RETURN 6557 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6558 regval = data16; 6559 regval /= 32; 6560 regval &= 31; 6561 if (regval >= 16) { 6562 regval -=32; 6563 } 6564 dsc_cbp->dfe5_bin = regval; 6565 6566 /* integ_reg(lane) = rd22_integ_reg (phy, lane) DSC_3_ADDR=0xc220 */ 6567 reg = 0xc220; 6568 SOC_IF_ERROR_RETURN 6569 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6570 regval = data16; 6571 regval &= 65535; 6572 if (regval >= 32768) { 6573 regval -=65536; 6574 } 6575 regval /= 84; 6576 dsc_cbp->integ_reg = regval; 6577 6578 /* integ_reg_xfer(lane) = rd22_integ_reg_xfer (phy, lane) */ 6579 reg = 0xc221; 6580 SOC_IF_ERROR_RETURN 6581 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6582 regval = data16; 6583 regval &= 65535; 6584 if (regval >= 32768) { 6585 regval -=65536; 6586 } 6587 dsc_cbp->integ_reg_xfer = regval; 6588 6589 /* clk90_offset(lane) = rd22_clk90_phase_offset (phy, lane) */ 6590 reg = 0xc223; 6591 SOC_IF_ERROR_RETURN 6592 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6593 regval = data16; 6594 regval /= 128; 6595 regval &= 127; 6596 dsc_cbp->clk90_offset = regval; 6597 6598 /* slicer_target(lane) = ((25*rd22_rx_thresh_sel (phy, lane)) + 125) */ 6599 reg = 0xc21c; 6600 SOC_IF_ERROR_RETURN 6601 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6602 regval = data16; 6603 regval /= 32; 6604 regval &= 3; 6605 dsc_cbp->slicer_target = regval * 25 + 125; 6606 6607 /* offset_pe(lane) = rd22_slicer_offset_pe (phy, lane) */ 6608 reg = 0xc22c; 6609 SOC_IF_ERROR_RETURN 6610 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6611 regval = data16; 6612 regval &= 63; 6613 if (regval >= 32) { 6614 regval -=64; 6615 } 6616 dsc_cbp->offset_pe = regval; 6617 6618 /* offset_ze(lane) = rd22_slicer_offset_ze (phy, lane) */ 6619 reg = 0xc22d; 6620 SOC_IF_ERROR_RETURN 6621 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6622 regval = data16; 6623 regval &= 63; 6624 if (regval >= 32) { 6625 regval -=64; 6626 } 6627 dsc_cbp->offset_ze = regval; 6628 6629 /* offset_me(lane) = rd22_slicer_offset_me (phy, lane) */ 6630 reg = 0xc22e; 6631 SOC_IF_ERROR_RETURN 6632 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6633 regval = data16; 6634 regval &= 63; 6635 if (regval >= 32) { 6636 regval -=64; 6637 } 6638 dsc_cbp->offset_me = regval; 6639 6640 /* offset_po(lane) = rd22_slicer_offset_po (phy, lane) */ 6641 reg = 0xc22c; 6642 SOC_IF_ERROR_RETURN 6643 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6644 regval = data16; 6645 regval /= 64; 6646 regval &= 63; 6647 if (regval >= 32) { 6648 regval -=64; 6649 } 6650 dsc_cbp->offset_po = regval; 6651 6652 /* offset_zo(lane) = rd22_slicer_offset_zo (phy, lane) */ 6653 reg = 0xc22d; 6654 SOC_IF_ERROR_RETURN 6655 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6656 regval = data16; 6657 regval /= 64; 6658 regval &= 63; 6659 if (regval >= 32) { 6660 regval -=64; 6661 } 6662 dsc_cbp->offset_zo = regval; 6663 6664 /* offset_mo(lane) = rd22_slicer_offset_mo (phy, lane) */ 6665 reg = 0xc22e; 6666 SOC_IF_ERROR_RETURN 6667 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data16)); 6668 regval = data16; 6669 regval /= 64; 6670 regval &= 63; 6671 if (regval >= 32) { 6672 regval -=64; 6673 } 6674 dsc_cbp->offset_mo = regval; 6675 } 6676 /* Restore to default single port register access */ 6677 if (PHY84328_SINGLE_PORT_MODE(pc)) { 6678 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, PHY84328_ALL_LANES)); 6679 } 6680 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 6681 PHY_84328_MICRO_RESUME(unit, port); 6682 6683 /* display */ 6684 LOG_CLI((BSL_META_U(unit, 6685 "\nDSC parameters for port %d\n"), port)); 6686 6687 LOG_CLI((BSL_META_U(unit, 6688 "LN PPM PPM_XFR clk90_ofs PF SL_TRGT VGA BIAS DFE1 DFE2 " 6689 "DFE3 DFE4 DFE5 PREC MAIN POSTC MTRC " 6690 "PE ZE ME PO ZO MO\n"))); 6691 for (i = 0; i < lanes; i++) { 6692 dsc_cbp = &(dsc_cb[i]); 6693 LOG_CLI((BSL_META_U(unit, 6694 "%02d %04d %07d %09d %04d %04d %04d %4s %04d %04d %04d %04d " 6695 "%04d %04d %04d %04d %04d %04d %04d %2d %3d %3d %2d\n"), 6696 i, dsc_cbp->integ_reg,dsc_cbp->integ_reg_xfer, 6697 dsc_cbp->clk90_offset, 6698 dsc_cbp->pf_ctrl, dsc_cbp->slicer_target, 6699 dsc_cbp->vga_sum, dsc_cbp->vga_bias_reduced, 6700 dsc_cbp->dfe1_bin, dsc_cbp->dfe2_bin, 6701 dsc_cbp->dfe3_bin, dsc_cbp->dfe4_bin, 6702 dsc_cbp->dfe5_bin, dsc_cbp->tx_pre_cursor, 6703 dsc_cbp->tx_main,dsc_cbp->tx_post_cursor, 6704 dsc_cbp->postc_metric, dsc_cbp->offset_pe, 6705 dsc_cbp->offset_ze,dsc_cbp->offset_me, 6706 dsc_cbp->offset_po, dsc_cbp->offset_zo, dsc_cbp->offset_mo)); 6707 6708 } 6709 6710 return SOC_E_NONE; 6711 } 6712 6713 6714 STATIC int 6715 _phy_84328_diag_eyescan_uc_ready(int unit, soc_port_t port) 6716 { 6717 int rv = SOC_E_NONE; 6718 uint16 data; 6719 soc_timeout_t to; 6720 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6721 6722 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6723 LOG_CLI((BSL_META_U(unit, 6724 " _phy_84328_diag_eyescan_uc_ready\n"))); 6725 } 6726 6727 /* Wait for uC ready */ 6728 soc_timeout_init(&to, 250000, 0); 6729 while (!soc_timeout_check(&to)) { 6730 rv = READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, &data); 6731 if (rv != SOC_E_NONE) { 6732 break; 6733 } 6734 if (data & PHY84328_DEV1_UC_CTRL_READY_FOR_CMD_MASK) { 6735 break; 6736 } 6737 } 6738 6739 if ((rv == SOC_E_NONE) && 6740 (data & PHY84328_DEV1_UC_CTRL_READY_FOR_CMD_MASK)) { 6741 rv = SOC_E_NONE; 6742 } else { 6743 LOG_ERROR(BSL_LS_SOC_PHY, 6744 (BSL_META_U(unit, 6745 "84328 EYE: uController not ready pass 1!: u=%d, p=%d " 6746 "uc_ctrl(1.%04x)=%04x\n"), unit, port, 6747 PHY84328_SYS_DEV1_UC_CTRL, data)); 6748 rv = SOC_E_TIMEOUT; 6749 } 6750 6751 return rv; 6752 } 6753 6754 STATIC int 6755 _phy_84328_diag_eyescan_offset(int unit, soc_port_t port, int16 supp_data, int req) 6756 { 6757 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6758 6759 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6760 LOG_CLI((BSL_META_U(unit, 6761 " _phy_84328_diag_eyescan_offset\n"))); 6762 } 6763 6764 /* offset 1.c20e */ 6765 SOC_IF_ERROR_RETURN( 6766 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, 6767 supp_data << PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_SHIFT, 6768 PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_MASK)); 6769 SOC_IF_ERROR_RETURN( 6770 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, 6771 0, PHY84328_SYS_DEV1_UC_CTRL_READY_FOR_CMD_MASK)); 6772 SOC_IF_ERROR_RETURN( 6773 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, 6774 0, PHY84328_SYS_DEV1_UC_CTRL_ERROR_FOUND_MASK)); 6775 SOC_IF_ERROR_RETURN( 6776 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, 6777 0, PHY84328_SYS_DEV1_UC_CTRL_CMD_INFO_MASK)); 6778 SOC_IF_ERROR_RETURN( 6779 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, 6780 (req | 6781 (supp_data << PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_SHIFT)), 6782 PHY84328_SYS_DEV1_UC_CTRL_GP_UC_REQ_MASK | 6783 PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_MASK)); 6784 6785 /* wait for uC ready for command */ 6786 return _phy_84328_diag_eyescan_uc_ready(unit, port); 6787 } 6788 6789 STATIC uint16 6790 _phy_84328_diag_eyescan_diag_ctrl_get(int unit, soc_port_t port) 6791 { 6792 uint16 data; 6793 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6794 6795 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 6796 PHY84328_SYS_DEV1_DSC_DIAG_CTRL0, 6797 &data)); 6798 return data; 6799 } 6800 6801 STATIC int 6802 _phy_84328_diag_eyescan_livelink_en(int unit, soc_port_t port, int en) 6803 { 6804 uint16 data, mask; 6805 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6806 6807 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6808 LOG_CLI((BSL_META_U(unit, 6809 "_phy_84328_diag_eyescan_livelink_en: en=%d\n"), en)); 6810 } 6811 6812 data = 0x2; 6813 mask = data; 6814 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 6815 PHY84328_SYS_DEV1_DSC_DIAG_CTRL0, 6816 data, mask)); 6817 6818 data = en ? PHY84328_SYS_DEV1_DSC_DIAG_CTRL0_DIAGNOSTICS_EN_BITS : 0; 6819 mask = PHY84328_SYS_DEV1_DSC_DIAG_CTRL0_DIAGNOSTICS_EN_MASK; 6820 6821 SOC_IF_ERROR_RETURN(MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 6822 PHY84328_SYS_DEV1_DSC_DIAG_CTRL0, 6823 data, mask)); 6824 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6825 LOG_CLI((BSL_META_U(unit, 6826 "_phy_84328_diag_eyescan_livelink_en: en=%d [%04x]\n"), 6827 en, _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6828 } 6829 6830 return SOC_E_NONE; 6831 } 6832 6833 STATIC int 6834 _phy_84328_diag_eyescan_livelink_clear(int unit, soc_port_t port, int unused) 6835 { 6836 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6837 6838 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, 0x3, 0x6)); 6839 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6840 LOG_CLI((BSL_META_U(unit, 6841 "_phy_84328_diag_eyescan_livelink_clear: [%04x]\n"), 6842 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6843 } 6844 return SOC_E_NONE; 6845 } 6846 6847 STATIC int 6848 _phy_84328_diag_eyescan_livelink_start(int unit, soc_port_t port, int unused) 6849 { 6850 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6851 6852 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, 0x0, 0x6)); 6853 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6854 LOG_CLI((BSL_META_U(unit, 6855 "_phy_84328_diag_eyescan_livelink_start: [%04x]\n"), 6856 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6857 } 6858 return SOC_E_NONE; 6859 } 6860 6861 STATIC int 6862 _phy_84328_diag_eyescan_livelink_stop(int unit, soc_port_t port, int unused) 6863 { 6864 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6865 6866 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, 0x1, 0x6)); 6867 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6868 LOG_CLI((BSL_META_U(unit, 6869 "_phy_84328_diag_eyescan_livelink_stop: [%04x]\n"), 6870 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6871 } 6872 return SOC_E_NONE; 6873 } 6874 6875 STATIC int 6876 _phy_84328_diag_eyescan_livelink_read(int unit, soc_port_t port, int *err_counter) 6877 { 6878 int i; 6879 uint16 data; 6880 uint32 counter; 6881 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6882 6883 counter = 0; 6884 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6885 LOG_CLI((BSL_META_U(unit, 6886 "_phy_84328_diag_eyescan_livelink_read: "))); 6887 } 6888 for (i = 0; i < 4; i++) { 6889 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, 0x2, 0x6)); 6890 6891 /* read back the maximum offset */ 6892 SOC_IF_ERROR_RETURN( 6893 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, &data)); 6894 data &= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_MASK; 6895 data >>= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_SHIFT; 6896 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6897 LOG_CLI((BSL_META_U(unit, 6898 "[%d]=%d "), i, data)); 6899 } 6900 counter += (data << (8 * i)); 6901 } 6902 *err_counter = counter; 6903 6904 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6905 LOG_CLI((BSL_META_U(unit, 6906 "\n_phy_84328_diag_eyescan_livelink_read: err_counter=%d\n"), 6907 *err_counter)); 6908 } 6909 return SOC_E_NONE; 6910 } 6911 6912 STATIC int 6913 _phy_84328_diag_eyescan_init_voffset_get(int unit, soc_port_t port, int *voffset) 6914 { 6915 uint16 data; 6916 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6917 6918 *voffset = 0; 6919 /* 1.c21c[15:10] */ 6920 SOC_IF_ERROR_RETURN(READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 6921 PHY84328_DEV1_DSC_ANA_CTRL3, 6922 &data)); 6923 *voffset = (data & PHY84328_DEV1_DSC_ANA_CTRL3_RSVD_FOR_ECO_MASK) >> 6924 PHY84328_DEV1_DSC_ANA_CTRL3_RSVD_FOR_ECO_SHIFT; 6925 6926 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6927 LOG_CLI((BSL_META_U(unit, 6928 "_phy_84328_diag_eyescan_init_voffset_get: " 6929 "voffset=%x [%04x]\n"), 6930 *voffset, 6931 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6932 } 6933 return SOC_E_NONE; 6934 } 6935 6936 STATIC int 6937 _phy_84328_diag_eyescan_hoffset_set(int unit, soc_port_t port, int *hoffset) 6938 { 6939 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6940 6941 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, *hoffset, 0x2)); 6942 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6943 LOG_CLI((BSL_META_U(unit, 6944 "_phy_84328_diag_eyescan_hoffset_set: hoffset=%x [%04x]\n"), 6945 *hoffset, _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6946 } 6947 return SOC_E_NONE; 6948 } 6949 6950 STATIC int 6951 _phy_84328_diag_eyescan_voffset_set(int unit, soc_port_t port, int *voffset) 6952 { 6953 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6954 6955 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, *voffset, 0x3)); 6956 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6957 LOG_CLI((BSL_META_U(unit, 6958 "_phy_84328_diag_eyescan_voffset_set: voffset=%x [%04x]\n"), 6959 *voffset, _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6960 } 6961 return SOC_E_NONE; 6962 } 6963 6964 STATIC int 6965 _phy_84328_diag_eyescan_max_left_hoffset_get(int unit, soc_port_t port, int *left_hoffset) 6966 { 6967 uint16 data; 6968 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6969 6970 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, 127, 0x2)); 6971 /* read back the maximum offset */ 6972 SOC_IF_ERROR_RETURN( 6973 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, &data)); 6974 data &= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_MASK; 6975 data >>= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_SHIFT; 6976 *left_hoffset = -data; 6977 6978 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 6979 LOG_CLI((BSL_META_U(unit, 6980 "_phy_84328_diag_eyescan_max_left_hoffset_get: " 6981 "max_left_hoffset=%d [%04x]\n"), 6982 *left_hoffset, 6983 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 6984 } 6985 6986 return SOC_E_NONE; 6987 } 6988 6989 STATIC int 6990 _phy_84328_diag_eyescan_max_right_hoffset_get(int unit, soc_port_t port, int *right_hoffset) 6991 { 6992 uint16 data; 6993 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 6994 6995 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, -128, 0x2)); 6996 /* read back the right offset */ 6997 SOC_IF_ERROR_RETURN( 6998 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, &data)); 6999 data &= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_MASK; 7000 data >>= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_SHIFT; 7001 *right_hoffset = data; 7002 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 7003 LOG_CLI((BSL_META_U(unit, 7004 "_phy_84328_diag_eyescan_max_right_hoffset_get: " 7005 "max right hoffset=%d [%04x]\n"), 7006 *right_hoffset, 7007 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 7008 } 7009 return SOC_E_NONE; 7010 } 7011 7012 STATIC int 7013 _phy_84328_diag_eyescan_min_voffset_get(int unit, soc_port_t port, int *min_voffset) 7014 { 7015 uint16 data; 7016 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 7017 7018 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, -128, 0x3)); 7019 7020 /* read back the min offset */ 7021 SOC_IF_ERROR_RETURN( 7022 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, &data)); 7023 data &= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_MASK; 7024 data >>= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_SHIFT; 7025 *min_voffset = data - 256; 7026 7027 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 7028 LOG_CLI((BSL_META_U(unit, 7029 "_phy_84328_diag_eyescan_min_voffset_get: " 7030 "min_voffset=%d [%04x]\n"), 7031 *min_voffset, 7032 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 7033 } 7034 return SOC_E_NONE; 7035 } 7036 7037 STATIC int 7038 _phy_84328_diag_eyescan_max_voffset_get(int unit, soc_port_t port, int *max_voffset) 7039 { 7040 uint16 data; 7041 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 7042 7043 SOC_IF_ERROR_RETURN(_phy_84328_diag_eyescan_offset(unit, port, 127, 0x3)); 7044 /* read back the max voffset */ 7045 SOC_IF_ERROR_RETURN( 7046 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_SYS_DEV1_UC_CTRL, &data)); 7047 data &= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_MASK; 7048 data >>= PHY84328_SYS_DEV1_UC_CTRL_SUPPLEMENT_INFO_SHIFT; 7049 *max_voffset = data; 7050 if (DBG_FLAGS(pc) & PHY84328_DBG_F_EYE) { 7051 LOG_CLI((BSL_META_U(unit, 7052 "_phy_84328_diag_eyescan_max_voffset_get: " 7053 "max_voffset=%d [%04x]\n"), 7054 *max_voffset, 7055 _phy_84328_diag_eyescan_diag_ctrl_get(unit, port))); 7056 } 7057 return SOC_E_NONE; 7058 } 7059 7060 STATIC int 7061 _phy_84328_diag_eyescan(int unit, soc_port_t port, uint32 inst, int op_cmd, void *arg) 7062 { 7063 int lane; 7064 int intf; 7065 phy84328_intf_side_t side; 7066 int rv = SOC_E_NONE; 7067 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 7068 7069 intf = PHY_DIAG_INST_INTF(inst); 7070 if (intf == PHY_DIAG_INTF_SYS) { 7071 side = PHY84328_INTF_SIDE_SYS; 7072 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_SYS); 7073 } else { 7074 side = PHY84328_INTF_SIDE_LINE; 7075 } 7076 lane = PHY_DIAG_INST_LN(inst); 7077 if (PHY84328_SINGLE_PORT_MODE(pc) && (lane != 0)) { 7078 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, side, lane)); 7079 } 7080 switch (op_cmd) { 7081 case PHY_DIAG_CTRL_EYE_ENABLE_LIVELINK: 7082 rv = _phy_84328_diag_eyescan_livelink_en(unit, port, 1); 7083 break; 7084 case PHY_DIAG_CTRL_EYE_DISABLE_LIVELINK: 7085 rv = _phy_84328_diag_eyescan_livelink_en(unit, port, 0); 7086 break; 7087 case PHY_DIAG_CTRL_EYE_CLEAR_LIVELINK: 7088 rv = _phy_84328_diag_eyescan_livelink_clear(unit, port, 0); 7089 break; 7090 case PHY_DIAG_CTRL_EYE_START_LIVELINK: 7091 rv = _phy_84328_diag_eyescan_livelink_start(unit, port, 0); 7092 break; 7093 case PHY_DIAG_CTRL_EYE_STOP_LIVELINK: 7094 rv = _phy_84328_diag_eyescan_livelink_stop(unit, port, 0); 7095 break; 7096 case PHY_DIAG_CTRL_EYE_READ_LIVELINK: 7097 rv = _phy_84328_diag_eyescan_livelink_read(unit, port, (int *) arg); 7098 break; 7099 case PHY_DIAG_CTRL_EYE_GET_INIT_VOFFSET: 7100 rv = _phy_84328_diag_eyescan_init_voffset_get(unit, port, (int *)arg); 7101 break; 7102 case PHY_DIAG_CTRL_EYE_SET_HOFFSET: 7103 rv = _phy_84328_diag_eyescan_hoffset_set(unit, port, (int *)arg); 7104 break; 7105 case PHY_DIAG_CTRL_EYE_SET_VOFFSET: 7106 rv = _phy_84328_diag_eyescan_voffset_set(unit, port, (int *)arg); 7107 break; 7108 case PHY_DIAG_CTRL_EYE_GET_MAX_LEFT_HOFFSET: 7109 rv = _phy_84328_diag_eyescan_max_left_hoffset_get(unit, port, (int *)arg); 7110 break; 7111 case PHY_DIAG_CTRL_EYE_GET_MAX_RIGHT_HOFFSET: 7112 rv = _phy_84328_diag_eyescan_max_right_hoffset_get(unit, port, (int *)arg); 7113 break; 7114 case PHY_DIAG_CTRL_EYE_GET_MIN_VOFFSET: 7115 rv = _phy_84328_diag_eyescan_min_voffset_get(unit, port, (int *)arg); 7116 break; 7117 case PHY_DIAG_CTRL_EYE_GET_MAX_VOFFSET: 7118 rv = _phy_84328_diag_eyescan_max_voffset_get(unit, port, (int *)arg); 7119 break; 7120 } 7121 if (PHY84328_SINGLE_PORT_MODE(pc) && (lane != 0)) { 7122 SOC_IF_ERROR_RETURN(_phy_84328_channel_select(unit, port, PHY84328_INTF_SIDE_LINE, 7123 PHY84328_ALL_LANES)); 7124 } 7125 if (intf == PHY_DIAG_INTF_SYS) { 7126 _phy_84328_intf_side_regs_select(unit, port, PHY84328_INTF_SIDE_LINE); 7127 } 7128 7129 return rv; 7130 } 7131 7132 STATIC int 7133 _phy_84328_diag_ctrl(int unit, soc_port_t port, uint32 inst, int op_type, int op_cmd, 7134 void *arg) 7135 { 7136 int lane; 7137 int intf; 7138 int rv = SOC_E_NONE; 7139 7140 LOG_INFO(BSL_LS_SOC_PHY, 7141 (BSL_META_U(unit, 7142 "84328 diag_ctrl: u=%d p=%d ctrl=0x%x\n"), unit, port, op_cmd)); 7143 7144 lane = PHY_DIAG_INST_LN(inst); 7145 intf = PHY_DIAG_INST_INTF(inst); 7146 if (intf == PHY_DIAG_INTF_DFLT) { 7147 intf = PHY_DIAG_INTF_LINE; 7148 } 7149 7150 switch (op_cmd) { 7151 case PHY_DIAG_CTRL_DSC: 7152 SOC_IF_ERROR_RETURN(_phy_84328_diag_dsc(unit, port, intf, lane)); 7153 break; 7154 case PHY_DIAG_CTRL_EYE_ENABLE_LIVELINK: 7155 case PHY_DIAG_CTRL_EYE_DISABLE_LIVELINK: 7156 case PHY_DIAG_CTRL_EYE_CLEAR_LIVELINK: 7157 case PHY_DIAG_CTRL_EYE_START_LIVELINK: 7158 case PHY_DIAG_CTRL_EYE_STOP_LIVELINK: 7159 case PHY_DIAG_CTRL_EYE_READ_LIVELINK: 7160 case PHY_DIAG_CTRL_EYE_GET_INIT_VOFFSET: 7161 case PHY_DIAG_CTRL_EYE_SET_HOFFSET: 7162 case PHY_DIAG_CTRL_EYE_SET_VOFFSET: 7163 case PHY_DIAG_CTRL_EYE_GET_MAX_LEFT_HOFFSET: 7164 case PHY_DIAG_CTRL_EYE_GET_MAX_RIGHT_HOFFSET: 7165 case PHY_DIAG_CTRL_EYE_GET_MIN_VOFFSET: 7166 case PHY_DIAG_CTRL_EYE_GET_MAX_VOFFSET: 7167 rv = _phy_84328_diag_eyescan(unit, port, inst, op_cmd, arg); 7168 break; 7169 case PHY_DIAG_CTRL_EYE_MARGIN_VEYE: 7170 case PHY_DIAG_CTRL_EYE_MARGIN_HEYE_LEFT: 7171 case PHY_DIAG_CTRL_EYE_MARGIN_HEYE_RIGHT: 7172 rv = SOC_E_UNAVAIL; 7173 break; 7174 7175 default: 7176 if (op_type == PHY_DIAG_CTRL_SET) { 7177 SOC_IF_ERROR_RETURN 7178 (_phy_84328_control_set(unit, port, intf, lane, op_cmd, PTR_TO_INT(arg))); 7179 } else if (op_type == PHY_DIAG_CTRL_GET) { 7180 SOC_IF_ERROR_RETURN 7181 (_phy_84328_control_get(unit, port, intf, lane, op_cmd, (uint32 *)arg)); 7182 } else { 7183 LOG_INFO(BSL_LS_SOC_PHY, 7184 (BSL_META_U(unit, 7185 "84328 diag_ctrl bad operation: u=%d p=%d ctrl=0x%x\n"), 7186 unit, port, op_cmd)); 7187 rv = SOC_E_UNAVAIL; 7188 } 7189 break; 7190 } 7191 7192 return rv; 7193 } 7194 7195 /* 7196 * Return whether AN is enabled or forced with internal SerDes on the system side 7197 */ 7198 STATIC int 7199 _phy_84328_intf_sys_forced(int unit, soc_port_t port, soc_port_if_t intf_type) 7200 { 7201 int rv; 7202 phy_ctrl_t *pc; 7203 7204 pc = EXT_PHY_SW_STATE(unit, port); 7205 7206 switch (intf_type) { 7207 case SOC_PORT_IF_SR: 7208 case SOC_PORT_IF_SR4: 7209 case SOC_PORT_IF_LR: 7210 case SOC_PORT_IF_LR4: 7211 case SOC_PORT_IF_XLAUI: 7212 case SOC_PORT_IF_XFI: 7213 case SOC_PORT_IF_SFI: 7214 case SOC_PORT_IF_CR: 7215 case SOC_PORT_IF_CR4: 7216 case SOC_PORT_IF_ZR: 7217 case SOC_PORT_IF_CAUI: 7218 rv = TRUE; 7219 break; 7220 case SOC_PORT_IF_GMII: 7221 rv = FALSE; 7222 break; 7223 case SOC_PORT_IF_KR: 7224 case SOC_PORT_IF_KR4: 7225 rv = SYS_FORCED_CL72(pc) ? TRUE : FALSE; 7226 break; 7227 default: 7228 rv = FALSE; 7229 } 7230 return rv; 7231 } 7232 7233 STATIC int 7234 _phy_84328_intf_line_forced(int unit, soc_port_t port, soc_port_if_t intf_type) 7235 { 7236 int rv; 7237 7238 switch (intf_type) { 7239 case SOC_PORT_IF_SR: 7240 case SOC_PORT_IF_SR4: 7241 case SOC_PORT_IF_LR: 7242 case SOC_PORT_IF_ZR: 7243 case SOC_PORT_IF_LR4: 7244 case SOC_PORT_IF_XLAUI: 7245 case SOC_PORT_IF_XFI: 7246 case SOC_PORT_IF_SFI: 7247 case SOC_PORT_IF_CR: 7248 case SOC_PORT_IF_CAUI: 7249 rv = TRUE; 7250 break; 7251 default: 7252 rv = FALSE; 7253 } 7254 return rv; 7255 } 7256 7257 STATIC int 7258 __phy_84328_speed_set(int unit, soc_port_t port, int speed) 7259 { 7260 int rv = SOC_E_NONE; 7261 int cur_an, cur_an_done; 7262 int cur_speed = 0; 7263 uint32 cur_fw_mode = 0; 7264 soc_port_if_t cur_type, new_type; 7265 phy_ctrl_t *pc, *int_pc; 7266 phy84328_intf_cfg_t *line_intf; 7267 phy84328_intf_cfg_t *sys_intf; 7268 7269 pc = EXT_PHY_SW_STATE(unit, port); 7270 int_pc = INT_PHY_SW_STATE(unit, port); 7271 line_intf = &(LINE_INTF(pc)); 7272 sys_intf = &(SYS_INTF(pc)); 7273 7274 line_intf->speed = speed; 7275 sys_intf->speed = speed; 7276 7277 /* Make sure datapath is correct one for this speed */ 7278 SOC_IF_ERROR_RETURN(_phy_84328_data_path_check(unit, port)); 7279 7280 if (int_pc != NULL) { 7281 if ((sys_intf->type == SOC_PORT_IF_GMII) || (sys_intf->type == SOC_PORT_IF_SGMII)) { 7282 SOC_IF_ERROR_RETURN(PHY_SPEED_SET(int_pc->pd, unit, port, sys_intf->speed)); 7283 } else if (_phy_84328_intf_sys_forced(unit, port, sys_intf->type) ) { 7284 /* 7285 * When setting system side 40G DAC/XLAUI-DFE, tell internal SerDes to match 7286 * with XLAUI. 7287 * 7288 * If flexports, the internal SerDes may be out of sync until it gets a chance 7289 * to convert the port, so these operations may be best effort. 7290 */ 7291 new_type = (sys_intf->type == SOC_PORT_IF_CR4) ? SOC_PORT_IF_XLAUI : sys_intf->type; 7292 SOC_IF_ERROR_RETURN(PHY_INTERFACE_GET(int_pc->pd, unit, port, &cur_type)); 7293 if (cur_type != new_type) { 7294 (void) PHY_INTERFACE_SET(int_pc->pd, unit, port, new_type); 7295 } 7296 7297 /* Check if it must change to forced */ 7298 SOC_IF_ERROR_RETURN(PHY_AUTO_NEGOTIATE_GET(int_pc->pd, unit, port, &cur_an, &cur_an_done)); 7299 if (cur_an == TRUE) { 7300 (void) PHY_AUTO_NEGOTIATE_SET(int_pc->pd, unit,port, FALSE); 7301 } 7302 7303 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2)) { 7304 /* Skip int_pc speed set during phy init */ 7305 } else if ((rv = PHY_SPEED_GET(int_pc->pd, unit, port, &cur_speed)) 7306 != SOC_E_NONE) { 7307 /* 7308 LOG_CLI((BSL_META_U(unit, 7309 "84328 u=%d p=%d speed get error\n"), unit, port)); 7310 */ 7311 return rv; 7312 } else if (cur_speed != sys_intf->speed) { 7313 (void) PHY_SPEED_SET(int_pc->pd, unit, port, sys_intf->speed); 7314 } 7315 7316 /* For system intf=cr4 use XLAUI_DFE on Serdes (in forced mode)*/ 7317 if (sys_intf->type != SOC_PORT_IF_CR4) { 7318 /* Skip int_pc fw mode set */ 7319 } else if ((rv = PHY_CONTROL_GET(int_pc->pd, unit, port, 7320 SOC_PHY_CONTROL_FIRMWARE_MODE, &cur_fw_mode)) 7321 != SOC_E_NONE) { 7322 /* 7323 LOG_CLI((BSL_META_U(unit, 7324 "84328 u=%d p=%d fwmode get error\n"), unit, port)); 7325 */ 7326 return rv; 7327 } else if (cur_fw_mode != SOC_PHY_FIRMWARE_FORCE_OSDFE) { 7328 (void) PHY_CONTROL_SET(int_pc->pd, unit, port, 7329 SOC_PHY_CONTROL_FIRMWARE_MODE, 7330 SOC_PHY_FIRMWARE_FORCE_OSDFE); 7331 } 7332 7333 } else { 7334 SOC_IF_ERROR_RETURN(PHY_AUTO_NEGOTIATE_SET(int_pc->pd, unit,port, TRUE)); 7335 } 7336 } 7337 7338 /* Update interface type/speed */ 7339 return _phy_84328_intf_line_sys_update(unit, port); 7340 } 7341 7342 STATIC int 7343 _phy_84328_intf_line_sys_init(int unit, soc_port_t port) 7344 { 7345 phy_ctrl_t *pc; 7346 phy84328_intf_cfg_t *line_intf; 7347 7348 pc = EXT_PHY_SW_STATE(unit, port); 7349 line_intf = &(LINE_INTF(pc)); 7350 7351 return __phy_84328_speed_set(unit, port, line_intf->speed); 7352 } 7353 7354 /* 7355 * Function: 7356 * phy_84328_speed_set 7357 * Purpose: 7358 * Set PHY speed 7359 * Parameters: 7360 * unit - StrataSwitch unit #. 7361 * port - StrataSwitch port #. 7362 * speed - link speed in Mbps 7363 * Returns: 7364 * SOC_E_NONE 7365 */ 7366 7367 STATIC int 7368 _phy_84328_speed_set(int unit, soc_port_t port, int speed) 7369 { 7370 int rv; 7371 phy_ctrl_t *pc; 7372 phy84328_intf_cfg_t *line_intf; 7373 phy84328_intf_cfg_t *sys_intf; 7374 7375 COMPILER_REFERENCE(unit); 7376 COMPILER_REFERENCE(port); 7377 7378 pc = EXT_PHY_SW_STATE(unit, port); 7379 line_intf = &(LINE_INTF(pc)); 7380 sys_intf = &(SYS_INTF(pc)); 7381 7382 LOG_INFO(BSL_LS_SOC_PHY, 7383 (BSL_META_U(unit, 7384 "phy_84328_speed_set: u=%d p=%d speed=%d\n"), 7385 unit, port,speed)); 7386 if (PHY84328_SINGLE_PORT_MODE(pc)) { 7387 if (! _phy_84328_intf_is_single_port(line_intf->type)) { 7388 LOG_INFO(BSL_LS_SOC_PHY, 7389 (BSL_META_U(unit, 7390 "84328 speed set does not match interface: " 7391 "u=%d p=%d speed=%d intf=%d\n"), 7392 unit, port, speed, sys_intf->type)); 7393 return SOC_E_PARAM; 7394 } 7395 switch (speed) { 7396 case 100000: 7397 case 40000: 7398 break; 7399 case 42000: 7400 /* 42G only valid for HG[42] */ 7401 if (! IS_HG_PORT(unit, port)) { 7402 speed = 40000; 7403 } 7404 break; 7405 default: 7406 return SOC_E_PARAM; 7407 } 7408 } else { 7409 if (_phy_84328_intf_is_single_port(line_intf->type)) { 7410 LOG_ERROR(BSL_LS_SOC_PHY, 7411 (BSL_META_U(unit, 7412 "84328 invalid intf in quad port: u=%d p=%d intf=%d\n"), 7413 unit, port, line_intf->type)); 7414 return SOC_E_PARAM; 7415 } 7416 switch (speed) { 7417 case 1000: 7418 if (!_phy_84328_intf_type_1000(line_intf->type)) { 7419 line_intf->type = SOC_PORT_IF_GMII; 7420 } 7421 /* 7422 * Changing speed to 1000 7423 * - if backplane interface then change to KX 7424 * - if not KX, then set to GMII 7425 */ 7426 if (sys_intf->type == SOC_PORT_IF_KR) { 7427 sys_intf->type = SOC_PORT_IF_KX; 7428 } else if (sys_intf->type != SOC_PORT_IF_KX) { 7429 sys_intf->type = line_intf->type; 7430 } 7431 break; 7432 case 100: 7433 case 10: 7434 if (line_intf->type != SOC_PORT_IF_SGMII) { 7435 line_intf->type = SOC_PORT_IF_SGMII; 7436 } 7437 sys_intf->type = line_intf->type; 7438 break; 7439 case 10000: 7440 /* 7441 * If changing from 1000 to 10000, then adjust interface 7442 */ 7443 if (line_intf->speed <= 1000) { 7444 /* 7445 * If changing speed from 1000 to 10000, set line interface to SFI 7446 */ 7447 if (!_phy_84328_intf_type_10000(line_intf->type)) { 7448 line_intf->type = SOC_PORT_IF_SR; 7449 } 7450 /* 7451 * Restore the configured system side interface 7452 */ 7453 sys_intf->type = CFG_SYS_INTF(pc); 7454 if (!_phy_84328_intf_type_10000(sys_intf->type)) { 7455 sys_intf->type = SOC_PORT_IF_XFI; 7456 } 7457 } 7458 break; 7459 case 40000: 7460 default: 7461 LOG_ERROR(BSL_LS_SOC_PHY, 7462 (BSL_META_U(unit, 7463 "84328 invalid speed: u=%d p=%d speed=%d\n"), 7464 unit, port, speed)); 7465 return SOC_E_PARAM; 7466 } 7467 } 7468 rv = __phy_84328_speed_set(unit, port, speed); 7469 if (SOC_FAILURE(rv)) { 7470 LOG_ERROR(BSL_LS_SOC_PHY, 7471 (BSL_META_U(unit, 7472 "84328 %s failed: u=%d p=%d\n"), FUNCTION_NAME(), unit, port)); 7473 } 7474 return rv; 7475 } 7476 7477 /* 7478 * Function: 7479 * phy_84328_speed_get 7480 * Purpose: 7481 * Get PHY speed 7482 * Parameters: 7483 * unit - StrataSwitch unit #. 7484 * port - StrataSwitch port #. 7485 * speed - current link speed in Mbps 7486 * Returns: 7487 * SOC_E_NONE 7488 */ 7489 7490 STATIC int 7491 _phy_84328_speed_get(int unit, soc_port_t port, int *speed) 7492 { 7493 phy84328_intf_cfg_t *line_intf; 7494 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 7495 7496 line_intf = &(LINE_INTF(pc)); 7497 *speed = line_intf->speed; 7498 7499 return SOC_E_NONE; 7500 } 7501 7502 7503 STATIC int 7504 _phy_84328_intf_type_set(int unit, soc_port_t port, soc_port_if_t pif, int must_update) 7505 { 7506 int rv = SOC_E_NONE; 7507 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 7508 phy84328_intf_cfg_t *line_intf; 7509 int update = 0; 7510 uint16 reg_data = 0, reg_mask = 0; 7511 uint16 data = 0, mask = 0; 7512 7513 line_intf = &(LINE_INTF(pc)); 7514 7515 reg_data = 0; 7516 reg_mask = 0; 7517 7518 FORCE_20BIT(pc) &= ~(FORCE_20BIT_AN); 7519 7520 if (_phy_84328_intf_is_single_port(pif)) { 7521 7522 if (!PHY84328_SINGLE_PORT_MODE(pc)) { 7523 LOG_ERROR(BSL_LS_SOC_PHY, 7524 (BSL_META_U(unit, 7525 "84328 invalid interface for quad port: u=%d p=%d\n"), 7526 unit, port)); 7527 return SOC_E_CONFIG; 7528 } 7529 /* 7530 * If rx polarity is flipped and the interface is CR4, then change the datapath 7531 * to 20-bit as rx polarity cannot be handle on the line side in 4-bit 7532 */ 7533 if (pif == SOC_PORT_IF_CR4) { 7534 if (AN_EN(pc)) { 7535 if (POL_RX_CFG(pc) && (CUR_DATAPATH(pc) != PHY84328_DATAPATH_20)) { 7536 CUR_DATAPATH(pc) = PHY84328_DATAPATH_20; 7537 update = 1; 7538 } 7539 if (POL_RX_CFG(pc)) { 7540 FORCE_20BIT(pc) |= FORCE_20BIT_AN ; 7541 } 7542 } else if (FORCE_20BIT(pc) == 0 && 7543 CUR_DATAPATH(pc) != CFG_DATAPATH(pc)) { 7544 CUR_DATAPATH(pc) = CFG_DATAPATH(pc); 7545 update = 1; 7546 } 7547 7548 SOC_IF_ERROR_RETURN( 7549 _phy_84328_intf_datapath_reg_get(unit, port, CUR_DATAPATH(pc), &data, &mask)); 7550 reg_data |= data; 7551 reg_mask |= mask; 7552 } 7553 if ((pif != line_intf->type) || must_update) { 7554 update = 1; 7555 7556 } 7557 } else if (_phy_84328_intf_is_quad_port(pif)) { 7558 if (PHY84328_SINGLE_PORT_MODE(pc)) { 7559 LOG_ERROR(BSL_LS_SOC_PHY, 7560 (BSL_META_U(unit, 7561 "84328 invalid interface for single port: u=%d p=%d\n"), 7562 unit, port)); 7563 return SOC_E_CONFIG; 7564 } 7565 7566 if ((line_intf->type != pif) || must_update) { 7567 update = 1; 7568 SOC_IF_ERROR_RETURN( 7569 _phy_84328_intf_type_reg_get(unit, port, pif, PHY84328_INTF_SIDE_LINE, 7570 ®_data, ®_mask)); 7571 7572 } 7573 } else { 7574 LOG_ERROR(BSL_LS_SOC_PHY, 7575 (BSL_META_U(unit, 7576 "84328 invalid interface for port: u=%d p=%d intf=%d\n"), 7577 unit, port, pif)); 7578 return SOC_E_CONFIG; 7579 } 7580 7581 if (update) { 7582 line_intf->type = pif; 7583 7584 SOC_IF_ERROR_RETURN( 7585 _phy_84328_intf_type_reg_get(unit, port, pif, PHY84328_INTF_SIDE_LINE, 7586 &data, &mask)); 7587 reg_data |= data; 7588 reg_mask |= mask; 7589 7590 SOC_IF_ERROR_RETURN(_phy_84328_intf_update(unit, port, reg_data, reg_mask)); 7591 7592 } 7593 7594 return rv; 7595 } 7596 7597 /* 7598 * Function: 7599 * phy_84328_interface_set 7600 * Purpose: 7601 * 7602 * 7603 * Parameters: 7604 * unit - StrataSwitch unit #. 7605 * port - StrataSwitch port #. 7606 * pif - one of SOC_PORT_IF_* 7607 * Returns: 7608 * SOC_E_NONE - success 7609 * SOC_E_UNAVAIL - unsupported interface 7610 */ 7611 7612 STATIC int 7613 _phy_84328_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 7614 { 7615 int rv; 7616 7617 LOG_INFO(BSL_LS_SOC_PHY, 7618 (BSL_META_U(unit, 7619 "84328 interface set: u=%d p=%d pif=%s\n"), 7620 unit, port, phy84328_intf_names[pif])); 7621 7622 7623 if (pif == SOC_PORT_IF_MII) { 7624 return phy_null_interface_set(unit, port, pif); 7625 } 7626 7627 if (pif == SOC_PORT_IF_XGMII) { 7628 return phy_null_interface_set(unit, port, pif); 7629 } 7630 7631 rv = _phy_84328_intf_type_set(unit, port, pif, FALSE); 7632 if (SOC_FAILURE(rv)) { 7633 LOG_INFO(BSL_LS_SOC_PHY, 7634 (BSL_META_U(unit, 7635 "84328 interface set check failed: u=%d p=%d\n"), 7636 unit, port)); 7637 } 7638 7639 if (_phy_84328_intf_line_forced(unit, port, pif)) { 7640 SOC_IF_ERROR_RETURN(_phy_84328_an_set(unit, port, 0)); 7641 } 7642 7643 return SOC_E_NONE; 7644 } 7645 7646 /* 7647 * Function: 7648 * phy_84328_interface_get 7649 * Purpose: 7650 * Get the current operating mode of the PHY. 7651 * Parameters: 7652 * unit - StrataSwitch unit #. 7653 * port - StrataSwitch port #. 7654 * pif - (OUT) one of SOC_PORT_IF_* 7655 * Returns: 7656 * SOC_E_NONE 7657 */ 7658 7659 STATIC int 7660 _phy_84328_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 7661 { 7662 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 7663 phy84328_intf_cfg_t *line_intf; 7664 7665 /* interface set now operates on line side interface */ 7666 line_intf = &(LINE_INTF(pc)); 7667 *pif = line_intf->type; 7668 7669 return SOC_E_NONE; 7670 } 7671 7672 STATIC int 7673 _phy84328_init_ucode_bcst_load(int unit, int port) 7674 { 7675 uint16 data16, mask16, num_words; 7676 uint8 *fw_ptr; 7677 int j, fw_length; 7678 phy_ctrl_t *pc; 7679 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7680 int dbg_flag = 1; 7681 #endif 7682 7683 pc = EXT_PHY_SW_STATE(unit, port); 7684 7685 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7686 if (dbg_flag) { 7687 LOG_INFO(BSL_LS_SOC_PHY, 7688 (BSL_META_U(unit, 7689 "PHY84328 bcst download device name %s: u=%d p=%d\n"), 7690 pc->dev_name? pc->dev_name: "NULL", unit, port)); 7691 } 7692 #endif 7693 /* find the right firmware */ 7694 if (pc->dev_name == dev_name_84328_a0) { 7695 fw_ptr = phy84328_ucode_bin; 7696 fw_length = phy84328_ucode_bin_len; 7697 } else if (pc->dev_name == dev_name_84328) { 7698 fw_ptr = phy84328B0_ucode_bin; 7699 fw_length = phy84328B0_ucode_bin_len; 7700 } else if (pc->dev_name == dev_name_84088) { 7701 fw_ptr = phy84328B0_ucode_bin; 7702 fw_length = phy84328B0_ucode_bin_len; 7703 } else { 7704 /* invalid device name */ 7705 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7706 LOG_WARN(BSL_LS_SOC_PHY, 7707 (BSL_META_U(unit, 7708 "firmware_bcst,invalid device name %s: u=%d p=%d\n"), 7709 pc->dev_name? pc->dev_name: "NULL", unit, port)); 7710 #endif 7711 return SOC_E_NONE; 7712 } 7713 7714 /* clear SPA ctrl reg bit 15 and bit 13. 7715 * bit 15, 0-use MDIO download to SRAM, 1 SPI-ROM download to SRAM 7716 * bit 13, 0 clear download done status, 1 skip download 7717 */ 7718 mask16 = PHY84328_DEV1_SPA_CONTROL_STATUS_REGISTER_SPI_PORT_USED_MASK 7719 | PHY84328_DEV1_SPA_CONTROL_STATUS_REGISTER_SPI_DWLD_DONE_MASK; 7720 data16 = 0; 7721 SOC_IF_ERROR_RETURN( 7722 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7723 PHY84328_DEV1_SPA_CONTROL_STATUS_REGISTER, 7724 data16,mask16)); 7725 7726 /* set SPA ctrl reg bit 14, 1 RAM boot, 0 internal ROM boot */ 7727 mask16 = PHY84328_DEV1_SPA_CONTROL_STATUS_REGISTER_SPI_BOOT_MASK; 7728 data16 = mask16; 7729 SOC_IF_ERROR_RETURN( 7730 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7731 PHY84328_DEV1_SPA_CONTROL_STATUS_REGISTER, 7732 data16,mask16)); 7733 7734 /* misc_ctrl1 reg bit 3 to 1 for 32k downloading size */ 7735 mask16 = PHY84328_DEV1_MISC_CTRL_SPI_DOWNLOAD_SIZE_MASK; 7736 data16 = mask16; 7737 SOC_IF_ERROR_RETURN( 7738 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7739 PHY84328_DEV1_MISC_CTRL, 7740 data16,mask16)); 7741 7742 /* deassert ucrst 1.ca10 bit 2=0 */ 7743 mask16 = PHY84328_DEV1_GEN_CTRL_UCRST_MASK; 7744 data16 = 0x00; /*clear; not self-clearing*/ 7745 SOC_IF_ERROR_RETURN( 7746 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GEN_CTRL, 7747 data16,mask16)); 7748 7749 /* wait for 2ms for M8051 start and 5ms to initialize the RAM */ 7750 sal_usleep(10000); /* Wait for 10ms */ 7751 7752 /* Write Starting Address, where the Code will reside in SRAM */ 7753 data16 = 0x8000; 7754 SOC_IF_ERROR_RETURN( 7755 WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7756 PHY84328_DEV1_MSG_IN, data16)); 7757 7758 /* make sure address word is read by the micro */ 7759 sal_udelay(10); /* Wait for 10us */ 7760 7761 /* Write SPI SRAM Count Size */ 7762 data16 = (fw_length)/2; 7763 SOC_IF_ERROR_RETURN( 7764 WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7765 PHY84328_DEV1_MSG_IN, data16)); 7766 7767 /* make sure read by the micro */ 7768 sal_udelay(10); /* Wait for 10us */ 7769 7770 if (pc->addr_write != NULL) { 7771 SOC_IF_ERROR_RETURN( 7772 WRITE_ADDR_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7773 PHY84328_C45_DEV_PMA_PMD, 7774 PHY84328_DEV1_MSG_IN)); 7775 } 7776 /* Fill in the SRAM */ 7777 num_words = (fw_length - 1); 7778 for (j = 0; j < num_words; j+=2) { 7779 7780 data16 = (fw_ptr[j] << 8) | fw_ptr[j+1]; 7781 7782 if (pc->data_write != NULL) { 7783 SOC_IF_ERROR_RETURN( 7784 WRITE_DATA_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7785 PHY84328_C45_DEV_PMA_PMD, data16)); 7786 } else { 7787 7788 /* Make sure the word is read by the Micro */ 7789 sal_udelay(10); 7790 SOC_IF_ERROR_RETURN( 7791 WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7792 PHY84328_DEV1_MSG_IN, data16)); 7793 } 7794 7795 } 7796 return SOC_E_NONE; 7797 } 7798 7799 STATIC int 7800 __phy84328_init_ucode_bcst(int unit, int port, int cmd) 7801 { 7802 uint16 data16; 7803 uint16 mask16; 7804 phy_ctrl_t *pc; 7805 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7806 int dbg_flag = 1; 7807 #endif 7808 pc = EXT_PHY_SW_STATE(unit, port); 7809 7810 #ifdef BCM_WARM_BOOT_SUPPORT 7811 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)){ 7812 return SOC_E_NONE; 7813 } 7814 #endif 7815 7816 if (cmd == PHYCTRL_UCODE_BCST_SETUP) { 7817 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7818 if (dbg_flag == 1) { 7819 LOG_INFO(BSL_LS_SOC_PHY, 7820 (BSL_META_U(unit, 7821 "PHY84328 bcst setup: u=%d p=%d\n"), unit, port)); 7822 } 7823 #endif 7824 /* Enable broadcast mode so all lanes get properly reset */ 7825 SOC_IF_ERROR_RETURN 7826 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7827 PHY84328_DEV1_BROADCAST_CTRL, 7828 PHY84328_DEV1_BROADCAST_CTRL_BROADCAST_MODE_ENABLE_MASK, 7829 PHY84328_DEV1_BROADCAST_CTRL_BROADCAST_MODE_ENABLE_MASK)); 7830 return SOC_E_NONE; 7831 } else if (cmd == PHYCTRL_UCODE_BCST_uC_SETUP) { 7832 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7833 if (dbg_flag == 1) { 7834 LOG_INFO(BSL_LS_SOC_PHY, 7835 (BSL_META_U(unit, 7836 "PHY84328 micro setup: u=%d p=%d\n"), unit, port)); 7837 } 7838 #endif 7839 /* apply bcst Reset to start download code from MDIO */ 7840 mask16 = PHY84328_DEV1_GEN_CTRL_UCRST_MASK; 7841 data16 = mask16; /*set*/ 7842 SOC_IF_ERROR_RETURN 7843 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_GEN_CTRL, 7844 data16,mask16)); 7845 7846 /* clear : 1.ca18 */ 7847 SOC_IF_ERROR_RETURN 7848 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7849 PHY84328_DEV1_GP_REG_0, 0)); 7850 /* clear : 1.ca19 */ 7851 SOC_IF_ERROR_RETURN 7852 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7853 PHY84328_DEV1_GP_REG_1, 0)); 7854 /* clear : 1.ca1a */ 7855 SOC_IF_ERROR_RETURN 7856 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7857 PHY84328_DEV1_GP_REG_2, 0)); 7858 7859 mask16 = PHY84328_DEV1_PMD_CONTROL_REGISTER_RESET_MASK; 7860 data16 = mask16; 7861 SOC_IF_ERROR_RETURN 7862 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_PMD_CONTROL_REGISTER, 7863 data16,mask16)); 7864 7865 /* Wait for 2.8 msec for 8051 to start */ 7866 sal_udelay(2800); 7867 7868 return SOC_E_NONE; 7869 } else if (cmd == PHYCTRL_UCODE_BCST_ENABLE) { 7870 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7871 if (dbg_flag == 1) { 7872 LOG_INFO(BSL_LS_SOC_PHY, 7873 (BSL_META_U(unit, 7874 "PHY84328 bcst enable: u=%d p=%d\n"), unit, port)); 7875 } 7876 #endif 7877 /* In case reset clears bcst register */ 7878 /* restore bcst register after reset */ 7879 /* Enable broadcast mode */ 7880 SOC_IF_ERROR_RETURN 7881 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7882 PHY84328_DEV1_BROADCAST_CTRL, 7883 PHY84328_DEV1_BROADCAST_CTRL_BROADCAST_MODE_ENABLE_MASK, 7884 PHY84328_DEV1_BROADCAST_CTRL_BROADCAST_MODE_ENABLE_MASK)); 7885 7886 return SOC_E_NONE; 7887 } else if (cmd == PHYCTRL_UCODE_BCST_LOAD) { 7888 7889 return _phy84328_init_ucode_bcst_load(unit, port); 7890 7891 } else if (cmd == PHYCTRL_UCODE_BCST_END) { 7892 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7893 if (dbg_flag == 1) { 7894 LOG_INFO(BSL_LS_SOC_PHY, 7895 (BSL_META_U(unit, 7896 "PHY84328 bcst end: u=%d p=%d\n"), unit, port)); 7897 } 7898 #endif 7899 /* make sure last code word is read by the micro */ 7900 sal_udelay(20); 7901 7902 7903 /* Read Hand-Shake message (Done) from Micro */ 7904 SOC_IF_ERROR_RETURN 7905 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7906 PHY84328_DEV1_MSG_OUT, &data16)); 7907 7908 /* Download done message */ 7909 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7910 if (dbg_flag == 1) { 7911 LOG_INFO(BSL_LS_SOC_PHY, 7912 (BSL_META_U(unit, 7913 "PHY84328 MDIO firmware download done message=0x%x: u=%d p=%d\n"), 7914 data16, unit, port)); 7915 } 7916 #endif 7917 sal_udelay(100); /* Wait for 100 usecs */ 7918 7919 /* Read checksum for Micro. 7920 The expected value is 0x0300 , 7921 where upper_byte=03 means mdio download is done 7922 and lower byte=00 means no checksum error */ 7923 SOC_IF_ERROR_RETURN 7924 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7925 PHY84328_DEV1_MSG_OUT, &data16)); 7926 7927 /* Download done message */ 7928 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7929 if (dbg_flag == 1) { 7930 LOG_INFO(BSL_LS_SOC_PHY, 7931 (BSL_META_U(unit, 7932 "PHY84328 MDIO firmware download status message state 0x%x checksum 0x%x: " 7933 "u=%d p=%d\n"), (data16 >> 8) & 0xff, data16 & 0xff, unit, port)); 7934 } 7935 #endif 7936 /* Need to check if checksum is correct */ 7937 SOC_IF_ERROR_RETURN 7938 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7939 PHY84328_DEV1_GP_REG_4, &data16)); 7940 7941 if (data16 == 0x600D) { 7942 /* read Rev-ID */ 7943 SOC_IF_ERROR_RETURN 7944 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7945 PHY84328_DEV1_VERSION, &data16)); 7946 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 7947 if (dbg_flag == 1) { 7948 LOG_INFO(BSL_LS_SOC_PHY, 7949 (BSL_META_U(unit, 7950 "PHY84328 Firmware revID=0x%x: u=%d p=%d \n"), 7951 data16, unit, port)); 7952 } 7953 #endif 7954 } 7955 7956 /* Disable broadcast mode */ 7957 SOC_IF_ERROR_RETURN 7958 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7959 PHY84328_DEV1_BROADCAST_CTRL, 7960 0, 7961 PHY84328_DEV1_BROADCAST_CTRL_BROADCAST_MODE_ENABLE_MASK)); 7962 7963 /* Go back to proper PMD mode */ 7964 data16 = (PHY84328_SINGLE_PORT_MODE(pc)) ? 7965 PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK : 0; 7966 SOC_IF_ERROR_RETURN 7967 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 7968 PHY84328_DEV1_SINGLE_PMD_CTRL, data16, 7969 PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK)); 7970 7971 /* Make sure micro completes its initialization */ 7972 sal_udelay(5000); 7973 return SOC_E_NONE; 7974 } else { 7975 LOG_ERROR(BSL_LS_SOC_PHY, 7976 (BSL_META_U(unit, 7977 "u=%d p=%d firmware_bcst: invalid cmd 0x%x\n"), 7978 unit, port,cmd)); 7979 } 7980 7981 return SOC_E_FAIL; 7982 } 7983 7984 7985 /* 7986 * Function: 7987 * phy_84328_precondition_before_probe 7988 * Purpose: 7989 * When the device is in 40G, ie. after a power reset, and the 10G 7990 * port being probed does not have the 40G address in PRTAD, the 7991 * device will not respond until the port that has the 40G address 7992 * is probed. To avoid not programming ports correctly, make 7993 * sure the device is in quad (4x10G) PMD mode when the SDK port is 10G. 7994 * Parameters: 7995 * unit - StrataSwitch unit #. 7996 * pc - phy ctrl descriptor. 7997 * Returns: 7998 * SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error> 7999 */ 8000 8001 STATIC int 8002 phy_84328_precondition_before_probe(int unit, phy_ctrl_t *pc) 8003 { 8004 int ids; 8005 int rv = SOC_E_NOT_FOUND; 8006 uint16 pmd_ctrl; 8007 uint16 id0, id1; 8008 uint16 saved_phy_id; 8009 8010 /* Not required when the port is single PMD */ 8011 if (PHY84328_SINGLE_PORT_MODE(pc)) { 8012 LOG_INFO(BSL_LS_SOC_PHY, 8013 (BSL_META_U(unit, 8014 "PMD must not be called when in single PMD\n"))); 8015 return rv; 8016 } 8017 8018 saved_phy_id = pc->phy_id; 8019 8020 /* Look for first address that responds */ 8021 for (ids = 0; ids < 4; ids++) { 8022 8023 pc->phy_id = (saved_phy_id & ~0x3) + ids; 8024 LOG_INFO(BSL_LS_SOC_PHY, 8025 (BSL_META_U(unit, 8026 "Try device with address %x\n"), pc->phy_id)); 8027 8028 /* 8029 * Make sure the device has the correct dev IDs 8030 * Note that this is being called either because the soc probe found 8031 * the ids or there was an id override. In the later case, the device 8032 * might not have the 84328 ids so this PMD setup will not be supported 8033 */ 8034 id0 = 0; 8035 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 8036 PHY84328_DEV1_PMD_IDENTIFIER_REGISTER_0, 8037 &id0); 8038 if (id0 != 0x600d) { 8039 continue; 8040 } 8041 id1 = 0; 8042 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 8043 PHY84328_DEV1_PMD_IDENTIFIER_REGISTER_1, 8044 &id1); 8045 if (id1 != 0x8500) { 8046 continue; 8047 } 8048 8049 /* Read device ids correctly so use this address to make sure device is in 10G */ 8050 pmd_ctrl = 0; 8051 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 8052 PHY84328_DEV1_SINGLE_PMD_CTRL, &pmd_ctrl); 8053 if (pmd_ctrl & PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK) { 8054 LOG_INFO(BSL_LS_SOC_PHY, 8055 (BSL_META_U(unit, 8056 "Device responded to address %x. Setting quad PMD mode\n"), 8057 pc->phy_id)); 8058 pmd_ctrl = 0; /* Clear single PMD */ 8059 SOC_IF_ERROR_RETURN( 8060 MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, 8061 PHY84328_DEV1_SINGLE_PMD_CTRL, pmd_ctrl, 8062 PHY84328_DEV1_SINGLE_PMD_CTRL_SINGLE_PMD_MODE_MASK)); 8063 } 8064 /* Found the address that responds and the device now is in 4x10G */ 8065 rv = SOC_E_NONE; 8066 break; 8067 } 8068 8069 pc->phy_id = saved_phy_id; 8070 8071 return rv; 8072 } 8073 8074 /* 8075 * Function: 8076 * phy_84328_probe 8077 * Purpose: 8078 * Complement the generic phy probe routine to identify this phy when its 8079 * phy id0 and id1 is same as some other phy's. 8080 * Parameters: 8081 * unit - StrataSwitch unit #. 8082 * pc - phy ctrl descriptor. 8083 * Returns: 8084 * SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error> 8085 */ 8086 STATIC int 8087 _phy_84328_probe(int unit, phy_ctrl_t *pc) 8088 { 8089 uint32 devid; 8090 uint16 chip_rev; 8091 8092 SOC_IF_ERROR_RETURN(_phy_84328_config_devid(pc->unit, pc->port, pc, &devid)); 8093 SOC_IF_ERROR_RETURN( 8094 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 8095 PHY84328_DEV1_CHIP_REV_REGISTER, 8096 &chip_rev)); 8097 8098 if (devid == PHY84328_ID_84328) { 8099 if (chip_rev == 0x00a0) { 8100 pc->dev_name = dev_name_84328_a0; 8101 } else { 8102 pc->dev_name = dev_name_84328; 8103 } 8104 } else if (devid == PHY84328_ID_84324){ 8105 pc->dev_name = dev_name_84324; 8106 } else if (devid == PHY84328_ID_84088){ 8107 pc->dev_name = dev_name_84088; 8108 } else if (devid == PHY84328_ID_84024){ 8109 pc->dev_name = dev_name_84024; 8110 } else { /* not found */ 8111 LOG_WARN(BSL_LS_SOC_PHY, 8112 (BSL_META_U(unit, 8113 "port %d: BCM84xxx type PHY device detected, please use " 8114 "phy_84<xxx> config variable to select the specific type\n"), 8115 pc->port)); 8116 return SOC_E_NOT_FOUND; 8117 } 8118 pc->size = sizeof(phy84328_dev_desc_t); 8119 return SOC_E_NONE; 8120 } 8121 8122 /* 8123 * Return the phy_id for the core 8124 * 8125 * Currently assumes the addresses for the cores are 8126 * 4 apart, e.g. core0_addr=n, core1_addr=n+4; core2_addr=n+8 8127 * 8128 * This can be modified to specify the address via a config property. 8129 * The config property spn_PORT_PHY_ADDR is already available to 8130 * specify the address for the port, which in a multicore port, 8131 * refers to core0. 8132 */ 8133 STATIC uint16 8134 _phy_84328_phy_id_get(phy_ctrl_t *pc, int core) 8135 { 8136 int phy_id = 0xff; 8137 int id_map[PHY84328_MAX_CORES] = { 0xff , 0xff, 0xff }; 8138 8139 id_map[core%PHY84328_MAX_CORES] = 8140 soc_property_port_suffix_num_get( 8141 pc->unit, pc->port, 8142 core, spn_PORT_PHY_ADDR, 8143 "core", id_map[core % PHY84328_MAX_CORES]); 8144 8145 phy_id = 8146 soc_property_port_get( 8147 pc->unit, pc->port, spn_PORT_PHY_ADDR, phy_id); 8148 8149 if (phy_id != id_map[core % PHY84328_MAX_CORES]) { 8150 return id_map[core % PHY84328_MAX_CORES]; 8151 } else { 8152 return pc->phy_id + (core * 4); 8153 } 8154 } 8155 8156 8157 STATIC int 8158 _phy_84328_bsc_rw(int unit, soc_port_t port, int dev_addr, int opr, 8159 int addr, int count, void *data_array,uint32 ram_start) 8160 { 8161 phy_ctrl_t *pc; 8162 soc_timeout_t to; 8163 uint16 data16; 8164 int i; 8165 int access_type; 8166 int data_type; 8167 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 8168 sal_usecs_t start; 8169 sal_usecs_t end; 8170 #endif 8171 8172 LOG_INFO(BSL_LS_SOC_PHY, 8173 (BSL_META_U(unit, 8174 "phy_84328_bsc_read: u=%d p=%d addr=%04x\n"), 8175 unit, port, addr)); 8176 8177 if (!data_array) { 8178 return SOC_E_PARAM; 8179 } 8180 8181 if (count > PHY84328_BSC_XFER_MAX) { 8182 return SOC_E_PARAM; 8183 } 8184 8185 pc = EXT_PHY_SW_STATE(unit, port); 8186 data_type = PHY84328_I2C_DATA_TYPE(opr); 8187 access_type = PHY84328_I2C_ACCESS_TYPE(opr); 8188 8189 if (access_type == PHY84328_I2CDEV_WRITE) { 8190 for (i = 0; i < count; i++) { 8191 if (data_type == PHY84328_I2C_8BIT) { 8192 SOC_IF_ERROR_RETURN 8193 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, ram_start + i, 8194 ((uint8 *)data_array)[i])); 8195 } else { /* 16 bit */ 8196 SOC_IF_ERROR_RETURN 8197 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, ram_start + i, 8198 ((uint16 *)data_array)[i])); 8199 } 8200 } 8201 } 8202 8203 data16 = ram_start; 8204 SOC_IF_ERROR_RETURN 8205 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 0x8004, data16)); 8206 SOC_IF_ERROR_RETURN 8207 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 0x8003, addr)); 8208 SOC_IF_ERROR_RETURN 8209 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 0x8002, count)); 8210 8211 data16 = 1; 8212 data16 |= (dev_addr<<9); 8213 if (access_type == PHY84328_I2CDEV_WRITE) { 8214 data16 |= PHY84328_WR_FREQ_400KHZ; 8215 } 8216 8217 SOC_IF_ERROR_RETURN 8218 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit,pc,0x8005,data16)); 8219 8220 if (access_type == PHY84328_I2CDEV_WRITE) { 8221 data16 = 0x8000 | PHY84328_BSC_WRITE_OP; 8222 } else { 8223 data16 = 0x8000 | PHY84328_BSC_READ_OP; 8224 } 8225 8226 if (data_type == PHY84328_I2C_16BIT) { 8227 data16 |= (1 << 12); 8228 } 8229 8230 /* Select first i2c port */ 8231 if (PHY84328_SINGLE_PORT_MODE(pc)) { 8232 SOC_IF_ERROR_RETURN 8233 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_MISC_CTRL, 8234 0, PHY84328_DEV1_MISC_CTRL_I2C_PORT_SEL_MASK)); 8235 } else { 8236 SOC_IF_ERROR_RETURN 8237 (MODIFY_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_DEV1_MISC_CTRL, 8238 (pc->phy_id & 0x3), PHY84328_DEV1_MISC_CTRL_I2C_PORT_SEL_MASK)); 8239 } 8240 8241 SOC_IF_ERROR_RETURN 8242 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, 0x8000, data16)); 8243 8244 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 8245 start = sal_time_usecs(); 8246 #endif 8247 soc_timeout_init(&to, 1000000, 0); 8248 while (!soc_timeout_check(&to)) { 8249 SOC_IF_ERROR_RETURN 8250 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, 0x8000, &data16)); 8251 if (((data16 & PHY84328_2W_STAT) == PHY84328_2W_STAT_COMPLETE)) { 8252 break; 8253 } 8254 } 8255 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 8256 end = sal_time_usecs(); 8257 #endif 8258 /* need some delays */ 8259 sal_usleep(10000); 8260 8261 #if defined(BROADCOM_DEBUG) || defined(DEBUG_PRINT) 8262 LOG_INFO(BSL_LS_SOC_PHY, 8263 (BSL_META_U(unit, 8264 "BSC command status %d time=%d\n"), 8265 (data16 & PHY84328_2W_STAT), SAL_USECS_SUB(end, start))); 8266 #endif 8267 8268 if (access_type == PHY84328_I2CDEV_WRITE) { 8269 return SOC_E_NONE; 8270 } 8271 8272 if ((data16 & PHY84328_2W_STAT) == PHY84328_2W_STAT_COMPLETE) { 8273 for (i = 0; i < count; i++) { 8274 SOC_IF_ERROR_RETURN 8275 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, (ram_start+i), &data16)); 8276 if (data_type == PHY84328_I2C_16BIT) { 8277 ((uint16 *)data_array)[i] = data16; 8278 LOG_INFO(BSL_LS_SOC_PHY, 8279 (BSL_META_U(unit, 8280 "%04x "), data16)); 8281 } else { 8282 ((uint8 *)data_array)[i] = (uint8)data16; 8283 LOG_INFO(BSL_LS_SOC_PHY, 8284 (BSL_META_U(unit, 8285 "%02x "), data16)); 8286 } 8287 } 8288 } 8289 return SOC_E_NONE; 8290 } 8291 8292 /* 8293 * Read a slave device such as NVRAM/EEPROM connected to the 84328's I2C 8294 * interface. This function will be mainly used for diagnostic or workaround 8295 * purpose. 8296 * Note: 8297 * The size of read_array buffer must be greater than or equal to the 8298 * parameter nbytes. 8299 * usage example: 8300 * Retrieve the first 100 byte data of the non-volatile storage device with 8301 * I2C bus device address 0x50(default SPF eeprom I2C address) on unit 0, 8302 * port 2. 8303 * uint8 data8[100]; 8304 * phy_84328_i2cdev_read(0,2,0x50,0,100,data8); 8305 */ 8306 int 8307 phy_84328_i2cdev_read(int unit, 8308 soc_port_t port, 8309 int dev_addr, /* 7 bit I2C bus device address */ 8310 int offset, /* starting data address to read */ 8311 int nbytes, /* number of bytes to read */ 8312 uint8 *read_array) /* buffer to hold retrieved data */ 8313 { 8314 return _phy_84328_bsc_rw(unit, port, dev_addr,PHY84328_I2CDEV_READ, 8315 offset, nbytes, (void *)read_array,PHY84328_READ_START_ADDR); 8316 8317 } 8318 8319 /* 8320 * Write to a slave device such as NVRAM/EEPROM connected to the 84328's I2C 8321 * interface. This function will be mainly used for diagnostic or workaround 8322 * purpose. 8323 * Note: 8324 * The size of write_array buffer should be equal to the parameter nbytes. 8325 * The EEPROM may limit the maximun write size to 16 bytes 8326 * usage example: 8327 * Write to first 100 byte space of the non-volatile storage device with 8328 * I2C bus device address 0x50(default SPF eeprom I2C address) on unit 0, 8329 * port 2, with written data specified in array data8. 8330 * uint8 data8[100]; 8331 * *** initialize the data8 array with written data *** 8332 * 8333 * phy_84328_i2cdev_write(0,2,0x50,0,100,data8); 8334 */ 8335 8336 int 8337 phy_84328_i2cdev_write(int unit, 8338 soc_port_t port, 8339 int dev_addr, /* I2C bus device address */ 8340 int offset, /* starting data address to write to */ 8341 int nbytes, /* number of bytes to write */ 8342 uint8 *write_array) /* buffer to hold written data */ 8343 { 8344 int j; 8345 int rv = SOC_E_NONE; 8346 8347 for (j = 0; j < (nbytes/PHY84328_BSC_WR_MAX); j++) { 8348 rv = _phy_84328_bsc_rw(unit, port, dev_addr,PHY84328_I2CDEV_WRITE, 8349 offset + j * PHY84328_BSC_WR_MAX, PHY84328_BSC_WR_MAX, 8350 (void *)(write_array + j * PHY84328_BSC_WR_MAX), 8351 PHY84328_WRITE_START_ADDR); 8352 if (rv != SOC_E_NONE) { 8353 return rv; 8354 } 8355 sal_usleep(20000); 8356 } 8357 if (nbytes%PHY84328_BSC_WR_MAX) { 8358 rv = _phy_84328_bsc_rw(unit, port, dev_addr,PHY84328_I2CDEV_WRITE, 8359 offset + j * PHY84328_BSC_WR_MAX, nbytes%PHY84328_BSC_WR_MAX, 8360 (void *)(write_array + j * PHY84328_BSC_WR_MAX), 8361 PHY84328_WRITE_START_ADDR); 8362 } 8363 return rv; 8364 } 8365 8366 /* 8367 * Function: 8368 * _phy_84328_reg_read 8369 * Purpose: 8370 * Routine to read PHY register 8371 * Parameters: 8372 * uint - BCM unit number 8373 * port - port number 8374 * flags - Flags which specify the register type 8375 * phy_reg_addr - Encoded register address 8376 * phy_data - (OUT) Value read from PHY register 8377 * Note: 8378 * This register read function is not thread safe. Higher level 8379 * function that calls this function must obtain a per port lock 8380 * to avoid overriding register page mapping between threads. 8381 */ 8382 STATIC int 8383 _phy_84328_reg_read(int unit, soc_port_t port, uint32 flags, 8384 uint32 phy_reg_addr, uint32 *phy_data) 8385 { 8386 uint16 data16; 8387 uint16 regdata; 8388 phy_ctrl_t *pc; /* PHY software state */ 8389 int rv = SOC_E_NONE; 8390 int rd_cnt; 8391 8392 pc = EXT_PHY_SW_STATE(unit, port); 8393 8394 rd_cnt = 1; 8395 8396 if (flags & SOC_PHY_I2C_DATA8) { 8397 8398 SOC_IF_ERROR_RETURN 8399 (phy_84328_i2cdev_read(unit, port, 8400 SOC_PHY_I2C_DEVAD(phy_reg_addr), 8401 SOC_PHY_I2C_REGAD(phy_reg_addr), 8402 rd_cnt, 8403 (uint8 *)&data16)); 8404 *phy_data = *((uint8 *)&data16); 8405 8406 } else if (flags & SOC_PHY_I2C_DATA16) { 8407 /* This operation is generally targeted to access 16-bit device, 8408 * such as PHY IC inside the SFP. However there is no 16-bit 8409 * scratch register space on the device. Use 1.800e 8410 * for this operation. 8411 */ 8412 SOC_IF_ERROR_RETURN 8413 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_I2C_TEMP_RAM, 8414 ®data)); 8415 8416 rv = _phy_84328_bsc_rw(unit, port, 8417 SOC_PHY_I2C_DEVAD(phy_reg_addr), 8418 PHY84328_I2C_OP_TYPE(PHY84328_I2CDEV_READ,PHY84328_I2C_16BIT), 8419 SOC_PHY_I2C_REGAD(phy_reg_addr),1, 8420 (void *)&data16,PHY84328_I2C_TEMP_RAM); 8421 8422 *phy_data = data16; 8423 8424 /* restore the ram register value */ 8425 SOC_IF_ERROR_RETURN 8426 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_I2C_TEMP_RAM, 8427 regdata)); 8428 } else { 8429 SOC_IF_ERROR_RETURN 8430 (READ_PHY_REG(unit, pc, phy_reg_addr, &data16)); 8431 *phy_data = data16; 8432 } 8433 8434 return rv; 8435 } 8436 8437 /* 8438 * Function: 8439 * _phy_84328_reg_write 8440 * Purpose: 8441 * Routine to write PHY register 8442 * Parameters: 8443 * uint - BCM unit number 8444 * port - port number 8445 * flags - Flags which specify the register type 8446 * phy_reg_addr - Encoded register address 8447 * phy_data - Value write to PHY register 8448 * Note: 8449 * This register read function is not thread safe. Higher level 8450 * function that calls this function must obtain a per port lock 8451 * to avoid overriding register page mapping between threads. 8452 */ 8453 STATIC int 8454 _phy_84328_reg_write(int unit, soc_port_t port, uint32 flags, 8455 uint32 phy_reg_addr, uint32 phy_data) 8456 { 8457 uint8 data8[4]; 8458 uint16 data16[2]; 8459 uint16 regdata[2]; 8460 phy_ctrl_t *pc; /* PHY software state */ 8461 int rv = SOC_E_NONE; 8462 int wr_cnt; 8463 pc = EXT_PHY_SW_STATE(unit, port); 8464 8465 wr_cnt = 1; 8466 8467 if (flags & SOC_PHY_I2C_DATA8) { 8468 data8[0] = (uint8)phy_data; 8469 SOC_IF_ERROR_RETURN 8470 (phy_84328_i2cdev_write(unit, port, 8471 SOC_PHY_I2C_DEVAD(phy_reg_addr), 8472 SOC_PHY_I2C_REGAD(phy_reg_addr), 8473 wr_cnt, 8474 data8)); 8475 } else if (flags & SOC_PHY_I2C_DATA16) { 8476 /* This operation is generally targeted to access 16-bit device, 8477 * such as PHY IC inside the SFP. However there is no 16-bit 8478 * scratch register space on the device. Use 1.800e 8479 * for this operation. 8480 */ 8481 /* save the temp ram register */ 8482 SOC_IF_ERROR_RETURN 8483 (READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_I2C_TEMP_RAM, 8484 ®data[0])); 8485 data16[0] = phy_data; 8486 rv = _phy_84328_bsc_rw(unit, port, 8487 SOC_PHY_I2C_DEVAD(phy_reg_addr), 8488 PHY84328_I2C_OP_TYPE(PHY84328_I2CDEV_WRITE,PHY84328_I2C_16BIT), 8489 SOC_PHY_I2C_REGAD(phy_reg_addr),wr_cnt, 8490 (void *)data16,PHY84328_I2C_TEMP_RAM); 8491 8492 /* restore the ram register value */ 8493 SOC_IF_ERROR_RETURN 8494 (WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, PHY84328_I2C_TEMP_RAM, 8495 regdata[0])); 8496 } else { 8497 SOC_IF_ERROR_RETURN 8498 (WRITE_PHY_REG(unit, pc, phy_reg_addr, (uint16)phy_data)); 8499 } 8500 8501 return rv; 8502 } 8503 8504 void 8505 _phy_84328_dbg_reg_read(int unit, soc_port_t port, int reg) 8506 { 8507 uint16 data; 8508 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8509 8510 if (pc == NULL) { 8511 return; 8512 } 8513 READ_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, &data); 8514 LOG_CLI((BSL_META_U(unit, 8515 "1.%04x=0x%04x\n"), reg, data)); 8516 } 8517 8518 void 8519 _phy_84328_dbg_reg_write(int unit, soc_port_t port, int reg, uint16 val) 8520 { 8521 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8522 8523 if (pc == NULL) { 8524 return; 8525 } 8526 WRITE_PHY84328_MMF_PMA_PMD_REG(unit, pc, reg, val); 8527 _phy_84328_dbg_reg_read(unit, port, reg); 8528 } 8529 8530 #ifdef PHY84328_MDIO_TRACING 8531 STATIC int 8532 _phy_84328_dbg_read(int unit, phy_ctrl_t *pc, uint32 addr, uint16 *data) 8533 { 8534 int rv; 8535 rv = (pc->read)(unit, pc->phy_id, addr, data); 8536 8537 if (DBG_FLAGS(pc) & PHY84328_DBG_F_REG) { 8538 LOG_CLI((BSL_META_U(unit, 8539 "p%d(%d): READ addr=%04x data=%04x\n"), 8540 pc->port, pc->phy_id, addr, *data)); 8541 } 8542 return rv; 8543 8544 } 8545 8546 STATIC int 8547 _phy_84328_dbg_write(int unit, phy_ctrl_t *pc, uint32 addr, uint16 data) 8548 { 8549 int rv; 8550 if (DBG_FLAGS(pc) & PHY84328_DBG_F_REG) { 8551 LOG_CLI((BSL_META_U(unit, 8552 "p%d(%d): WRITE addr=%04x data=%04x\n"), 8553 pc->port, pc->phy_id, addr, data)); 8554 } 8555 rv = (pc->write)(unit, pc->phy_id, addr, data); 8556 return rv; 8557 } 8558 8559 STATIC int 8560 _phy_84328_dbg_modify(int unit, phy_ctrl_t *pc, uint32 addr, uint16 data, uint16 mask) 8561 { 8562 int rv; 8563 if (DBG_FLAGS(pc) & PHY84328_DBG_F_REG) { 8564 LOG_CLI((BSL_META_U(unit, 8565 "p%d(%d): MODIFY addr=%04x data=%04x mask=%04x\n"), 8566 pc->port, pc->phy_id, 8567 addr, data, mask)); 8568 } 8569 rv = phy_reg_modify(unit, pc, addr, data, mask); 8570 return rv; 8571 } 8572 #endif /* PHY84328_MDIO_TRACING */ 8573 8574 8575 8576 /******************************************************************************/ 8577 8578 8579 /* 8580 * Function: 8581 * phy_84328_probe 8582 * Purpose: 8583 * Complement the generic phy probe routine to identify this phy when its 8584 * phy id0 and id1 is same as some other phy's. 8585 * Parameters: 8586 * unit - StrataSwitch unit #. 8587 * pc - phy ctrl descriptor. 8588 * Returns: 8589 * SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error> 8590 */ 8591 STATIC int 8592 phy_84328_probe(int unit, phy_ctrl_t *pc) 8593 { 8594 int rv; 8595 char *dev_name = ""; 8596 uint16 prim_phy_id; 8597 int core, all_cores; 8598 soc_port_t port; 8599 8600 pc->size = 0; 8601 port = pc->port; 8602 all_cores = PHY84328_CORES(unit, port); 8603 if (all_cores > PHY84328_MAX_CORES) { 8604 LOG_ERROR(BSL_LS_SOC_PHY, 8605 (BSL_META_U(unit, 8606 "u=%d p=%d: too many cores %d\n"), 8607 unit, port, all_cores)); 8608 return SOC_E_NOT_FOUND; 8609 } 8610 prim_phy_id = pc->phy_id; 8611 for (core = 0; core < all_cores; core++) { 8612 8613 /* 8614 * During probe, reuse the pc for the port (first core only) as there are no 8615 * pc's allocated yet for the other cores 8616 */ 8617 pc->phy_id = _phy_84328_phy_id_get(pc, core); 8618 8619 rv = _phy_84328_probe(unit, pc); 8620 pc->phy_id = prim_phy_id; 8621 if (rv != SOC_E_NONE) { 8622 return rv; 8623 } 8624 8625 /* 8626 * Make sure the probed device name for all cores matches the first 8627 * core device name 8628 */ 8629 if (core == 0) { 8630 dev_name = pc->dev_name; 8631 } else if (pc->dev_name != dev_name) { 8632 LOG_ERROR(BSL_LS_SOC_PHY, 8633 (BSL_META_U(unit, 8634 "u=%d p=%d: all cores must have same device: core0=%s != core%d=%s\n"), 8635 unit, port, dev_name, core, pc->dev_name)); 8636 return SOC_E_NOT_FOUND; 8637 } 8638 } 8639 8640 /* 8641 * Allocate one pc + one control block for each core 8642 */ 8643 pc->size = sizeof(phy84328_dev_desc_t) + ((all_cores - 1) * PHY84328_CORE_STATE_SIZE); 8644 8645 return SOC_E_NONE; 8646 } 8647 8648 STATIC void 8649 _phy_84328_init_setup(int unit, soc_port_t port) 8650 { 8651 int core, all_cores; 8652 phy_ctrl_t *core_pc; 8653 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8654 8655 /* DBG_FLAGS(pc) = 0; */ 8656 DBG_FLAGS(pc) = PHY84328_DBG_F_API_SET | PHY84328_DBG_F_DWLD; 8657 8658 all_cores = PHY84328_CORES(unit, port); 8659 for (core = 0; core < all_cores; core++) { 8660 core_pc = PHY84328_CORE_PC(pc, core); 8661 8662 if (core > 0) { 8663 /* Copy state from core 0 pc to other core pcs */ 8664 sal_memcpy(core_pc, pc , sizeof(phy_ctrl_t)); 8665 8666 /* Populate phy_id for core1..core2 */ 8667 core_pc->phy_id = _phy_84328_phy_id_get(pc, core); 8668 } 8669 8670 8671 CORE_NUM(core_pc) = core; 8672 if (all_cores > 1) { 8673 core_pc->phy_mode = PHYCTRL_MULTI_CORE_PORT; 8674 } 8675 } 8676 } 8677 8678 STATIC int 8679 phy_84328_init(int unit, soc_port_t port) 8680 { 8681 int rv; 8682 int pass; 8683 int core, all_cores; 8684 phy_ctrl_t *core_pc; 8685 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8686 8687 pass = PHYCTRL_INIT_STATE(pc); 8688 8689 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) { 8690 _phy_84328_init_setup(unit, port); 8691 } 8692 8693 /* 8694 if (DBG_FLAGS(pc) & PHY84328_DBG_F_API_SET) { 8695 bsl_normal(BSL_APPL_SHELL, unit, 8696 "%s(%d, %d)\n", FUNCTION_NAME(), unit, port); 8697 } 8698 */ 8699 8700 all_cores = PHY84328_CORES(unit, port); 8701 for (core = 0; core < all_cores; core++) { 8702 core_pc = PHY84328_CORE_PC(pc, core); 8703 8704 PHY84328_CORE_STATE_SET(unit, port, core, pc); 8705 /* copy init state to core_pc */ 8706 PHYCTRL_INIT_STATE_SET(core_pc, pass); 8707 rv = _phy_84328_init(unit, port); 8708 PHY84328_CORE_STATE_SET(unit, port, 0, pc); 8709 8710 if (rv != SOC_E_NONE) { 8711 return rv; 8712 } 8713 } 8714 8715 return SOC_E_NONE; 8716 } 8717 8718 STATIC int 8719 _phy84328_init_ucode_bcst(int unit, int port, int cmd) 8720 { 8721 int rv; 8722 int core, all_cores; 8723 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8724 8725 all_cores = PHY84328_CORES(unit, port); 8726 8727 /* 8728 * The actual load needs to happen only on the first core as the 8729 * other cores will be in broadcast mode 8730 */ 8731 if (cmd == PHYCTRL_UCODE_BCST_LOAD) { 8732 all_cores = 1; 8733 } 8734 for (core = 0; core < all_cores; core++) { 8735 PHY84328_CORE_STATE_SET(unit, port, core, pc); 8736 rv = __phy84328_init_ucode_bcst(unit, port, cmd); 8737 PHY84328_CORE_STATE_SET(unit, port, 0, pc); 8738 if (rv != SOC_E_NONE) { 8739 return rv; 8740 } 8741 } 8742 8743 return SOC_E_NONE; 8744 } 8745 8746 STATIC int 8747 phy_84328_firmware_set(int unit, int port, int offset, uint8 *array,int datalen) 8748 { 8749 /* 8750 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8751 */ 8752 8753 /* 8754 * When array==NULL, this function is used to broadcast the firmware. 8755 * array==NULL should be specified only for internal use 8756 */ 8757 /* 8758 if (DBG_FLAGS(pc) & PHY84328_DBG_F_API_SET) { 8759 bsl_normal(BSL_APPL_SHELL, unit, 8760 "%s(%d, %d)\n", FUNCTION_NAME(), unit, port); 8761 } 8762 */ 8763 8764 if (array == NULL) { 8765 return _phy84328_init_ucode_bcst(unit, port, offset); 8766 } else { 8767 /* 8768 bsl_warning(BSL__X, unit, 8769 "u=%d p=%d firmware download method not supported\n", 8770 unit, port); 8771 */ 8772 return SOC_E_UNAVAIL; 8773 } 8774 8775 return SOC_E_NONE; 8776 } 8777 8778 STATIC int 8779 phy_84328_enable_set(int unit, soc_port_t port, int enable) 8780 { 8781 PHY84328_CALL_SET(unit, port, (_phy_84328_enable_set(unit, port, enable))); 8782 } 8783 8784 STATIC int 8785 phy_84328_speed_set(int unit, soc_port_t port, int speed) 8786 { 8787 PHY84328_CALL_SET(unit, port, (_phy_84328_speed_set(unit, port, speed))); 8788 } 8789 8790 STATIC int 8791 phy_84328_speed_get(int unit, soc_port_t port, int *speed) 8792 { 8793 int port_speed = 0; 8794 8795 PHY84328_CALL_GET(unit, port, (_phy_84328_speed_get(unit, port, speed)), 8796 speed, port_speed); 8797 } 8798 8799 STATIC int 8800 phy_84328_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 8801 { 8802 PHY84328_CALL_SET(unit, port, (_phy_84328_interface_set(unit, port, pif))); 8803 } 8804 8805 STATIC int 8806 phy_84328_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 8807 { 8808 soc_port_if_t port_pif = 0; 8809 8810 PHY84328_CALL_GET(unit, port, (_phy_84328_interface_get(unit, port, pif)), 8811 pif, port_pif); 8812 } 8813 8814 STATIC int 8815 phy_84328_lb_set(int unit, soc_port_t port, int enable) 8816 { 8817 PHY84328_CALL_SET(unit, port, (_phy_84328_lb_set(unit, port, enable))); 8818 } 8819 8820 STATIC int 8821 phy_84328_lb_get(int unit, soc_port_t port, int *enable) 8822 { 8823 int port_enable = 0; 8824 8825 PHY84328_CALL_GET(unit, port, (_phy_84328_lb_get(unit, port, enable)), 8826 enable, port_enable); 8827 } 8828 8829 STATIC int 8830 phy_84328_link_get(int unit, soc_port_t port, int *link) 8831 { 8832 int port_link = 0; 8833 8834 PHY84328_CALL_GET(unit, port, (_phy_84328_link_get(unit, port, link)), 8835 link, port_link); 8836 } 8837 8838 8839 STATIC int 8840 phy_84328_an_set(int unit, soc_port_t port, int an) 8841 { 8842 PHY84328_CALL_SET(unit, port, (_phy_84328_an_set(unit, port, an))); 8843 } 8844 8845 8846 STATIC int 8847 phy_84328_control_set(int unit, soc_port_t port, 8848 soc_phy_control_t type, uint32 value) 8849 { 8850 PHY84328_CALL_SET(unit, port, 8851 (phy_84328_control_port_set(unit, port, type, value))); 8852 } 8853 8854 STATIC int 8855 phy_84328_control_get(int unit, soc_port_t port, 8856 soc_phy_control_t type, uint32 *value) 8857 { 8858 uint32 port_value = 0; 8859 8860 PHY84328_CALL_GET(unit, port, 8861 (phy_84328_control_port_get(unit, port, type, value)), 8862 value, port_value); 8863 } 8864 8865 STATIC int 8866 phy_84328_reg_write(int unit, soc_port_t port, uint32 flags, 8867 uint32 phy_reg_addr, uint32 phy_data) 8868 { 8869 #ifdef BCM_WARM_BOOT_SUPPORT 8870 if ( SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit) ) { 8871 return SOC_E_NONE; 8872 } 8873 #endif 8874 PHY84328_CALL_SET(unit, port, 8875 (_phy_84328_reg_write(unit, port, 8876 flags, phy_reg_addr, phy_data))); 8877 } 8878 8879 STATIC int 8880 phy_84328_reg_read(int unit, soc_port_t port, uint32 flags, 8881 uint32 phy_reg_addr, uint32 *phy_data) 8882 { 8883 uint32 port_phy_data = 0; 8884 8885 PHY84328_CALL_GET(unit, port, 8886 (_phy_84328_reg_read( 8887 unit, port, flags, phy_reg_addr, phy_data)), 8888 phy_data, port_phy_data); 8889 } 8890 8891 STATIC int 8892 phy_84328_ability_advert_set(int unit, soc_port_t port, 8893 soc_port_ability_t *ability) 8894 { 8895 PHY84328_CALL_SET(unit, port, 8896 (_phy_84328_ability_advert_set(unit, port, ability))); 8897 } 8898 8899 STATIC int 8900 phy_84328_ability_advert_get(int unit, soc_port_t port, 8901 soc_port_ability_t *ability) 8902 { 8903 int rv; 8904 int core, all_cores; 8905 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8906 soc_port_ability_t port_ability; 8907 8908 8909 if (DBG_FLAGS(pc) & PHY84328_DBG_F_API_SET) { 8910 LOG_INFO(BSL_LS_SOC_PHY, 8911 (BSL_META_U(unit, 8912 "%s(%d, %d)\n"), FUNCTION_NAME(), unit, port)); 8913 } 8914 8915 all_cores = PHY84328_CORES(unit, port); 8916 for (core = 0; core < all_cores; core++) { 8917 8918 PHY84328_CORE_STATE_SET(unit, port, core, pc); 8919 rv = _phy_84328_ability_advert_get(unit, port, ability); 8920 PHY84328_CORE_STATE_SET(unit, port, 0, pc); 8921 8922 if (rv != SOC_E_NONE) { 8923 return rv; 8924 } 8925 8926 if (core > 0) { 8927 if (sal_memcmp((const void *) &port_ability, 8928 (const void *) ability, 8929 sizeof(soc_port_ability_t))){ 8930 /* 8931 bsl_error(BSL__X, unit, 8932 "84328 %s : ability does not match " 8933 "for all cores: u=%d p=%d\n", 8934 FUNCTION_NAME(), unit, port ); 8935 */ 8936 } 8937 } else if (all_cores > 1) { 8938 sal_memcpy(&port_ability, ability , sizeof(soc_port_ability_t)); 8939 } 8940 } 8941 8942 return SOC_E_NONE; 8943 } 8944 8945 8946 STATIC int 8947 phy_84328_diag_ctrl(int unit, soc_port_t port, uint32 inst, int op_type, int op_cmd, void *arg) 8948 { 8949 int rv = SOC_E_NONE; 8950 int core, all_cores; 8951 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8952 uint32 port_arg; 8953 8954 8955 if (DBG_FLAGS(pc) & PHY84328_DBG_F_API_SET) { 8956 LOG_INFO(BSL_LS_SOC_PHY, 8957 (BSL_META_U(unit, 8958 "%s(%d, %d)\n"), FUNCTION_NAME(), unit, port)); 8959 } 8960 8961 all_cores = PHY84328_CORES(unit, port); 8962 for (core = 0; core < all_cores; core++) { 8963 8964 PHY84328_CORE_STATE_SET(unit, port, core, pc); 8965 8966 switch(op_type) 8967 { 8968 case PHY_DIAG_CTRL_SET: 8969 case PHY_DIAG_CTRL_CMD: 8970 rv = 8971 (_phy_84328_diag_ctrl(unit, port, inst, op_type, op_cmd, arg)); 8972 break; 8973 8974 case PHY_DIAG_CTRL_GET: 8975 rv = 8976 (_phy_84328_diag_ctrl(unit, port, inst, op_type, op_cmd, arg)); 8977 8978 if (core > 0) { 8979 if (sal_memcmp((const void *) &port_arg, 8980 (const void *) arg, 8981 sizeof(port_arg))){ 8982 LOG_ERROR(BSL_LS_SOC_PHY, 8983 (BSL_META_U(unit, 8984 "84328 %s : arg does not match " 8985 "for all cores: u=%d p=%d\n"), 8986 FUNCTION_NAME(), unit, port )); 8987 } 8988 } else if (all_cores > 1) { 8989 sal_memcpy(&port_arg, arg , sizeof(port_arg)); 8990 } 8991 break; 8992 8993 default: 8994 LOG_INFO(BSL_LS_SOC_PHY, 8995 (BSL_META_U(unit, 8996 "84328 diag_ctrl bad operation: u=%d p=%d ctrl=0x%x\n"), 8997 unit, port, op_cmd)); 8998 rv = SOC_E_UNAVAIL; 8999 break; 9000 } 9001 9002 PHY84328_CORE_STATE_SET(unit, port, 0, pc); 9003 9004 if (rv != SOC_E_NONE) { 9005 return rv; 9006 } 9007 9008 } 9009 return SOC_E_NONE; 9010 } 9011 9012 9013 STATIC int 9014 phy_84328_ability_remote_get(int unit, soc_port_t port, 9015 soc_port_ability_t *ability) 9016 { 9017 int rv; 9018 int core, all_cores; 9019 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 9020 soc_port_ability_t port_ability; 9021 9022 9023 if (DBG_FLAGS(pc) & PHY84328_DBG_F_API_SET) { 9024 LOG_INFO(BSL_LS_SOC_PHY, 9025 (BSL_META_U(unit, 9026 "%s(%d, %d)\n"), FUNCTION_NAME(), unit, port)); 9027 } 9028 9029 all_cores = PHY84328_CORES(unit, port); 9030 for (core = 0; core < all_cores; core++) { 9031 9032 PHY84328_CORE_STATE_SET(unit, port, core, pc); 9033 rv = _phy_84328_ability_remote_get(unit, port, ability); 9034 PHY84328_CORE_STATE_SET(unit, port, 0, pc); 9035 9036 if (rv != SOC_E_NONE) { 9037 return rv; 9038 } 9039 9040 if (core > 0) { 9041 if (sal_memcmp((const void *) &port_ability, 9042 (const void *) ability, 9043 sizeof(soc_port_ability_t))){ 9044 /* 9045 LOG_ERROR(BSL_LS_SOC_PHY, 9046 (BSL_META_U(unit, 9047 "84328 %s : ability does not match " 9048 "for all cores: u=%d p=%d\n"), 9049 FUNCTION_NAME(), unit, port )); 9050 */ 9051 } 9052 } else if (all_cores > 1) { 9053 sal_memcpy(&port_ability, ability , sizeof(soc_port_ability_t)); 9054 } 9055 } 9056 9057 return SOC_E_NONE; 9058 } 9059 9060 /* 9061 * Variable: 9062 * phy_84328_drv 9063 * Purpose: 9064 * Phy Driver for 40G PHY. 9065 */ 9066 phy_driver_t phy_84328drv_xe = { 9067 "84328 40-Gigabit PHY Driver", 9068 phy_84328_init, /* Init */ 9069 phy_null_reset, /* Reset (dummy) */ 9070 phy_84328_link_get, /* Link get */ 9071 phy_84328_enable_set, /* Enable set */ 9072 phy_null_enable_get, /* Enable get */ 9073 phy_null_set, /* Duplex set */ 9074 phy_null_one_get, /* Duplex get */ 9075 phy_84328_speed_set, /* Speed set */ 9076 phy_84328_speed_get, /* Speed get */ 9077 phy_null_set, /* Master set */ 9078 phy_null_zero_get, /* Master get */ 9079 phy_84328_an_set, /* ANA set */ 9080 phy_84328_an_get, /* ANA get */ 9081 NULL, /* Local Advert set */ 9082 NULL, /* Local Advert get */ 9083 phy_null_mode_get, /* Remote Advert get */ 9084 phy_84328_lb_set, /* PHY loopback set */ 9085 phy_84328_lb_get, /* PHY loopback set */ 9086 phy_84328_interface_set, /* IO Interface set */ 9087 phy_84328_interface_get, /* IO Interface get */ 9088 NULL, /* PHY abilities mask */ 9089 NULL, 9090 NULL, 9091 phy_null_mdix_set, 9092 phy_null_mdix_get, 9093 phy_null_mdix_status_get, 9094 NULL, 9095 NULL, 9096 phy_null_medium_get, 9097 NULL, /* phy_cable_diag */ 9098 NULL, /* phy_link_change */ 9099 phy_84328_control_set, /* phy_control_set */ 9100 phy_84328_control_get, /* phy_control_get */ 9101 phy_84328_reg_read, /* phy_reg_read */ 9102 phy_84328_reg_write, /* phy_reg_write */ 9103 NULL, /* phy_reg_modify */ 9104 NULL, /* phy_notify */ 9105 phy_84328_probe, /* pd_probe */ 9106 phy_84328_ability_advert_set, /* pd_ability_advert_set */ 9107 phy_84328_ability_advert_get, /* pd_ability_advert_get */ 9108 phy_84328_ability_remote_get, /* pd_ability_remote_get */ 9109 phy_84328_ability_local_get, /* pd_ability_local_get */ 9110 phy_84328_firmware_set, /* pd_firmware_set */ 9111 NULL, /* pd_timesync_config_set */ 9112 NULL, /* pd_timesync_config_get */ 9113 NULL, /* pd_timesync_control_set */ 9114 NULL, /* pd_timesync_control_get */ 9115 phy_84328_diag_ctrl, /* .pd_diag_ctrl */ 9116 NULL, /* pd_lane_control_set */ 9117 NULL, /* pd_lane_control_get */ 9118 NULL, /* pd_lane_reg_read */ 9119 NULL, /* pd_lane_reg_write */ 9120 NULL, /* pd_oam_config_set */ 9121 NULL, /* pd_oam_config_get */ 9122 NULL, /* pd_oam_control_set */ 9123 NULL, /* pd_oam_control_get */ 9124 NULL, /* pd_timesync_enhanced_capture_get */ 9125 NULL, /* pd_multi_get */ 9126 phy_84328_precondition_before_probe /* pd_precondition_before_probe */ 9127 }; 9128 #else /* INCLUDE_PHY_84328 */ 9129 int _phy_84328_not_empty; 9130 #endif /* INCLUDE_PHY_84328 */