phy8806x.c (290247B)
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: phy8806x.c 8 * Purpose: Support Broadcom BCP8806X external PHY. 9 */ 10 11 /* 12 * This module implements an NTSW SDK Phy driver for the BCM8806X PHY. 13 * 14 * LAYERING. 15 * 16 * This driver is built on top of the PHYMOD library, which is a PHY 17 * driver library that can operate on a family of PHYs, including 18 * BCM8806X. PHYMOD can be built in a standalone enviroment and be 19 * provided independently from the SDK. PHYMOD APIs consist of 20 * "core" APIs and "phy" APIs. 21 * 22 * 23 * KEY IDEAS AND MAIN FUNCTIONS 24 * 25 * Some key ideas in this architecture are: 26 * 27 * o A PHMOD "phy" consists of one more more lanes, all residing in a single 28 * core. An SDK "phy" is a logical port, which can consist of one or 29 * more lanes in a single core, OR, can consist of multiples lanes in 30 * more than one core. 31 * o PHYMOD code is "stateless" in the sense that all calls to PHYMOD 32 * APIs are fully parameterized and no per-phy state is held by a PHYMOD 33 * driver. 34 * o PHYMOD APIs do not map 1-1 with SDK .pd_control_set or .pd_control_get 35 * APIs (nor ".pd_xx" calls, nor to .phy_tsce_per_lane_control_set and 36 * .phy_tsce_per_lane_control_get APIs. 37 * 38 * The purpose of this code, then, is to provide the necessary translations 39 * between the SDK interfaces and the PHYMOD interfaces. This includes: 40 * 41 * o Looping over the cores in a logical PHY in order to operate on the 42 * supporting PHMOD PHYs 43 * o Determining the configuration data for the phy, based on programmed 44 * defaults and SOC properties. 45 * o Managing the allocation and freeing of phy data structures required for 46 * working storage. Locating these structures on procedure invocation. 47 * o Mapping SDK API concepts to PHYMOD APIs. In some cases, local state is 48 * required in this module in order to present the legacy API. 49 * 50 * 51 * MAIN DATA STRUCTURES 52 * 53 * phy_ctrl_t 54 * The PHY control structure defines the SDK notion of a PHY 55 * (existing) structure owned by SDK phy driver modules. In order 56 * to support PHYMOD PHYs, one addition was made to this structure 57 * (soc_phymod_ctrl_t phymod_ctrl;) 58 * 59 * tsce_config_t 60 * Driver specific data. This structure is used by tsce to hold 61 * logical port specific working storage. 62 * 63 * soc_phymod_ctrl_t 64 * PHYMOD drivers. Resides in phy_ctrl_t specifies how many cores 65 * are in this phy and contains an array of pointers to 66 * soc_phymod_phy_t structures, which define a PHYMOD PHY. 67 * 68 * soc_phymod_phy_t 69 * This structure contains a pointer to phymod_phy_access_t and a 70 * pointer to the associated soc_phymod_core_t. Instances if this 71 * structure are created during device probe/init and are maintained 72 * by the SOC. 73 * 74 * soc_phymod_core_t 75 * This structure contains per-core information. Multiple PHYMOD 76 * PHYS can point to a single core. 77 * 78 * phymod_phy_access_t 79 * This structure contains information about how to read/write PHY 80 * registers. A required parameter for PHYMOD PHY APIs 81 * 82 * phymod_core_access_t 83 * This structure contains information about how to read/write PHY 84 * registers. A required parameter for PHYMOD core APIs. 85 */ 86 87 #include <shared/bsl.h> 88 89 #include <sal/types.h> 90 #include <sal/types.h> 91 #include <sal/core/spl.h> 92 #include <shared/bsl.h> 93 #include <soc/drv.h> 94 #include <soc/debug.h> 95 #include <soc/error.h> 96 #include <soc/phyreg.h> 97 #include <soc/port_ability.h> 98 #include <soc/phy.h> 99 #include <soc/phy/phyctrl.h> 100 #include <soc/phy/drv.h> 101 #include <soc/phy/phymod_ids.h> 102 103 #include "phydefs.h" /* Must include before other phy related includes */ 104 105 #include "phyconfig.h" /* Must include before other phy related includes */ 106 #include "phyident.h" 107 #include "phyreg.h" 108 #include "phynull.h" 109 #include "xgxs.h" 110 #include "serdesid.h" 111 #ifdef BCM_CMICM_SUPPORT 112 #include <soc/cmicm.h> 113 #endif 114 115 #if defined(INCLUDE_PHY_8806X) 116 117 #include "phy8806x.h" 118 #include "phy8806x_ctr.h" 119 #include "phy8806x_syms.h" 120 #include <phymod/phymod.h> 121 #include <phymod/phymod_debug.h> 122 #include <phymod/phymod_diagnostics.h> 123 #include <appl/diag/diag.h> 124 #include "phy8806x_funcs.h" 125 126 #ifdef PORTMOD_SUPPORT 127 #include <soc/portmod/portmod.h> 128 #endif 129 130 #if defined(INCLUDE_FCMAP) 131 #include <soc/fcmapphy.h> 132 #endif 133 #include "../../../libs/phymod/chip/phy8806x/phy8806x_xmod_api.h" 134 135 #define PMD_TEST_FIRMWARE 136 #define PHY8806X_DEBUG 0 137 138 #define NUM_LANES 4 /* num of lanes per core */ 139 #define MAX_NUM_LANES 4 /* max num of lanes per port */ 140 141 142 #define PHYMOD_INTF_CR4 (1 << SOC_PORT_IF_CR4) 143 144 #define PHY8806X_40G_10G_INTF(_if) ((_if) == SOC_PORT_IF_KR4 || (_if) == SOC_PORT_IF_XLAUI || \ 145 (_if) == SOC_PORT_IF_CR4 || (_if) == SOC_PORT_IF_SR || \ 146 (_if) == SOC_PORT_IF_KR || (_if) == SOC_PORT_IF_CR || \ 147 (_if) == SOC_PORT_IF_XFI || (_if) == SOC_PORT_IF_SFI) 148 149 #define PHY8806X_40G_10G_INTF_ALL (PHY8806X_IF_KR4 | PHY8806X_IF_XLAUI | PHY8806X_IF_CR4 | PHY8806X_IF_SR | \ 150 PHY8806X_IF_KR | PHY8806X_IF_CR | PHY8806X_IF_XFI | PHY8806X_IF_SFI) 151 152 #define GEARBOX_LINE_LANE_CNT 4 153 154 #define PHY8806X_LANE_NAME_LEN 30 155 156 #define PHY8806X_MEASSURE_DOWNLOAD_TIME 157 158 /* index to TX drive configuration table for each VCO setting. 159 */ 160 typedef enum txdrv_inxs { 161 TXDRV_XFI_INX = 0, /* 10G XFI */ 162 TXDRV_XLAUI_INX, /* 40G XLAUI mode */ 163 TXDRV_SFI_INX, /* 10G SR fiber mode */ 164 TXDRV_SFIDAC_INX, /* 10G SFI DAC mode */ 165 TXDRV_SR4_INX, /* 40G SR4 */ 166 TXDRV_AN_INX, /* a common entry for autoneg mode */ 167 TXDRV_DFT_INX, /* temp for any missing speed modes */ 168 TXDRV_LAST_INX /* always last */ 169 } TXDRV_INXS_t; 170 171 /* Port mode */ 172 typedef enum { 173 _BFCMAPPER_PORT_MODE_QUAD = 0, 174 _BFCMAPPER_PORT_MODE_TRI_0122 = 1, 175 _BFCMAPPER_PORT_MODE_TRI_0023 = 2, 176 _BFCMAPPER_PORT_MODE_DUAL = 3, 177 _BFCMAPPER_PORT_MODE_SINGLE = 4 178 } _bfcmapper_port_mode_t; 179 180 typedef enum { 181 REPEATER_AN_PHASE_NONE = -1, 182 REPEATER_AN_PHASE_0, 183 REPEATER_AN_PHASE_1, 184 REPEATER_AN_PHASE_2 185 } repeater_an_phase_t; 186 187 #define REPEATER_AN_PHASE0_LOCKED 1 188 #define REPEATER_AN_PHASE0_CL74 2 189 #define REPEATER_AN_PHASE0_CL91 4 190 #define REPEATER_AN_PHASE1_LOCKED 8 191 #define REPEATER_AN_PHASE0_RETRY 10 192 #define REPEATER_AN_PHASE1_RETRY 10 193 194 #define REPEATER_FS_RESET_TRIAL 20 195 196 #define TXDRV_ENTRY_NUM (TXDRV_LAST_INX) 197 198 #define PHY8806X_IF_NULL (1 << SOC_PORT_IF_NULL) 199 #define PHY8806X_IF_SR (1 << SOC_PORT_IF_SR) 200 #define PHY8806X_IF_SR2 (1 << SOC_PORT_IF_MII) 201 #define PHY8806X_IF_SR4 (1 << SOC_PORT_IF_SR4) 202 #define PHY8806X_IF_KR (1 << SOC_PORT_IF_KR) 203 #define PHY8806X_IF_KR2 (1 << SOC_PORT_IF_TBI) 204 #define PHY8806X_IF_KR4 (1 << SOC_PORT_IF_KR4) 205 #define PHY8806X_IF_CR (1 << SOC_PORT_IF_CR) 206 #define PHY8806X_IF_CR2 (1 << SOC_PORT_IF_RGMII) 207 #define PHY8806X_IF_CR4 (1 << SOC_PORT_IF_CR4) 208 #define PHY8806X_IF_XFI (1 << SOC_PORT_IF_XFI) 209 #define PHY8806X_IF_SFI (1 << SOC_PORT_IF_SFI) 210 #define PHY8806X_IF_XLAUI (1 << SOC_PORT_IF_XLAUI) 211 #define PHY8806X_IF_XGMII (1 << SOC_PORT_IF_XGMII) 212 #define PHY8806X_IF_ILKN (1 << SOC_PORT_IF_ILKN) 213 214 #define PHY8806X_40G_10G_INTF(_if) ((_if) == SOC_PORT_IF_KR4 || (_if) == SOC_PORT_IF_XLAUI || \ 215 (_if) == SOC_PORT_IF_CR4 || (_if) == SOC_PORT_IF_SR || \ 216 (_if) == SOC_PORT_IF_KR || (_if) == SOC_PORT_IF_CR || \ 217 (_if) == SOC_PORT_IF_XFI || (_if) == SOC_PORT_IF_SFI) 218 219 #define PHY8806X_40G_10G_INTF_ALL (PHY8806X_IF_KR4 | PHY8806X_IF_XLAUI | PHY8806X_IF_CR4 | PHY8806X_IF_SR | \ 220 PHY8806X_IF_KR | PHY8806X_IF_CR | PHY8806X_IF_XFI | PHY8806X_IF_SFI) 221 222 #define PHY8806X_CL73_HPAM_VS_SW 0x8 223 #define PHY8806X_CL73_HPAM 0x6 224 #define PHY8806X_CL73_CL37 0x5 225 #define PHY8806X_MSA 0x4 226 #define PHY8806X_CL73_MSA 0x3 227 #define PHY8806X_CL73_WO_BAM 0x2 228 #define PHY8806X_CL73_W_BAM 0x1 229 #define PHY8806X_CL73_DISABLE 0x0 230 231 #define TO(_pc) (((phy8806x_config_t *)((_pc) + 1))->to) 232 #define FIRMWARE(_pc) (((phy8806x_config_t *)((_pc) + 1))->firmware) 233 #define FIRMWARE_LEN(_pc) (((phy8806x_config_t *)((_pc) + 1))->firmware_len) 234 #define DL_DIVIDEND(_pc) (((phy8806x_config_t *)((_pc) + 1))->dl_dividend) 235 #define DL_DIVISOR(_pc) (((phy8806x_config_t *)((_pc) + 1))->dl_divisor) 236 #define ETH_CTR(_pc) (((phy8806x_config_t *)((_pc) + 1))->inbctr) 237 #define PMD_SIZE(_pc) (((phy8806x_config_t *)((_pc) + 1))->pmd_size) 238 #define PMD_CRC(_pc) (((phy8806x_config_t *)((_pc) + 1))->pmd_crc) 239 #define TOP_DEV_REV_ID(_pc) (((phy8806x_config_t *)((_pc) + 1))->top_dev_rev_id) 240 #define LED_TX(_pc) (((phy8806x_config_t *)((_pc) + 1))->led_tx) 241 #define LED_RX(_pc) (((phy8806x_config_t *)((_pc) + 1))->led_rx) 242 #define LED_SPEED(_pc) (((phy8806x_config_t *)((_pc) + 1))->led_speed) 243 244 #define PORT_ADDRESS(_base_addr, _sys, _mig) ( ((_base_addr) & ((0x1 << 27) | 0xffff)) | ((((_sys) << 3) + ((_mig) << 2) + 1) << 19) ) 245 #define LOW16(_x) ( (_x) & 0xffff ) 246 #define HIGH16(_x) ( ((_x) >> 16) & 0xffff ) 247 248 #define RETRY_COUNT 5 249 250 #define WRITE_BLK_SIZE 4 251 252 extern uint8 bcm_8806x_firmware[]; 253 254 extern int bcm_8806x_firmware_size; 255 256 static char *dev_name_8806x = "BCM8806x"; 257 static sal_mutex_t xmod_mutex[SOC_MAX_NUM_DEVICES]; 258 259 #define XMOD_MUTEX_TIMEOUT 10000000 /* 10ms */ 260 261 #define PHY_IS_BCM8806X_A0(_pc) (PHY_IS_BCM8806X(_pc) \ 262 && ((TOP_DEV_REV_ID(_pc) & 0x00ff0000) == 0x00010000)) 263 #define PHY_IS_BCM8806X_B0(_pc) (PHY_IS_BCM8806X(_pc) \ 264 && ((TOP_DEV_REV_ID(_pc) & 0x00ff0000) == 0x00110000)) 265 #define PHY_IS_BCM88060(_pc) (PHY_IS_BCM8806X(_pc) \ 266 && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x60)) 267 #define PHY_IS_BCM88061(_pc) (PHY_IS_BCM8806X(_pc) \ 268 && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x61)) 269 #define PHY_IS_BCM88064(_pc) (PHY_IS_BCM8806X(_pc) \ 270 && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x64)) 271 #define PHY_IS_BCM88068(_pc) (PHY_IS_BCM8806X(_pc) \ 272 && ((TOP_DEV_REV_ID(_pc) & 0xff) == 0x68)) 273 274 #ifdef BE_HOST 275 #define HOST2LE32(_x) (_shr_swap32((_x))) 276 #define LE2HOST32(_x) (_shr_swap32((_x))) 277 #else 278 #define HOST2LE32(_x) (_x) 279 #define LE2HOST32(_x) (_x) 280 #endif 281 282 STATIC int phy8806x_cl72_enable_set(soc_phymod_ctrl_t *pmc, uint32 value); 283 STATIC int phy_8806x_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability); 284 STATIC int phy_8806x_ability_advert_set(int unit, soc_port_t port, 285 soc_port_ability_t *ability); 286 STATIC int _phy_8806x_write_to_arm(int unit, phy_ctrl_t *pc, uint32 addr, uint8 *data,int len); 287 STATIC int _phy_8806x_xmod_command_ack(int unit, phy_ctrl_t *pc); 288 STATIC int _phy_8806x_xmod_command_send(int unit, phy_ctrl_t *pc, int mode_opcode, uint32 arg[], int arg_size); 289 STATIC int _phy_8806x_xmod_result_recv(int unit, phy_ctrl_t *pc, uint32 result[], int result_size); 290 STATIC int _phy_8806x_axi_write(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size); 291 STATIC int _phy_8806x_axi_read(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size); 292 STATIC int _pmd_enable(int unit, phy_ctrl_t *pc, int sys); 293 STATIC int _pmd_disable(int unit, phy_ctrl_t *pc, int sys); 294 STATIC int _pmd_start(int unit, phy_ctrl_t *pc, int sys); 295 STATIC int _tsc_reg_read(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 *value); 296 STATIC int _tsc_reg_write(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 value, uint16 mask); 297 int tsc_reg_read_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg); 298 int tsc_reg_write_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg, uint16 value, uint16 mask); 299 int phy_8806x_xmod_command(int unit, int port, int mode_opcode, uint32 arg[], int arg_size, uint32 result[], int result_size); 300 STATIC int phy_8806x_an_get(int unit, soc_port_t port, int *an, int *an_done); 301 STATIC int phy8806x_forced_speed_line_side_set(soc_phymod_ctrl_t *pmc, uint32 value); 302 STATIC int phy8806x_forced_speed_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *value); 303 STATIC int phy8806x_flow_control_mode_set(soc_phymod_ctrl_t *pmc, uint32 value, uint8 ingress); 304 STATIC int phy8806x_flow_control_mode_get(soc_phymod_ctrl_t *pmc, uint8 ingress, uint32 *value); 305 STATIC int phy8806x_psm_cos_bmp_set(soc_phymod_ctrl_t *pmc, uint32 value); 306 STATIC int phy8806x_psm_cos_bmp_get(soc_phymod_ctrl_t *pmc, uint32* value); 307 STATIC int phy8806x_pfc_use_ip_cos_set(soc_phymod_ctrl_t *pmc, uint32 value); 308 STATIC int phy8806x_pfc_use_ip_cos_get(soc_phymod_ctrl_t *pmc, uint32* value); 309 STATIC int _phy8806x_dump_buffer(int unit, int port, unsigned char *arg); 310 STATIC int phy_8806x_an_set(int unit, soc_port_t port, int enable); 311 STATIC int phy8806x_autoneg_line_side_set(soc_phymod_ctrl_t *pmc, uint32 enable); 312 STATIC int phy8806x_autoneg_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *enable); 313 STATIC int phy_8806x_fw_stat_read(int unit, int port, int offset, uint32_t result[], int result_size); 314 extern int phy8806x_tsc_pmd_lock_status (const phymod_access_t *pa, uint8_t *pmd_rx_lock); 315 316 /* 317 * Function: 318 * _8806x_reg_read 319 * Doc: 320 * register read operations 321 * Parameters: 322 * unit - (IN) unit number 323 * core_addr - (IN) core address 324 * reg_addr - (IN) address to read 325 * val - (OUT) read value 326 */ 327 STATIC int 328 _8806x_reg_read(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t *val) 329 { 330 uint16 data16; 331 int rv = SOC_E_NONE; 332 soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc; 333 phymod_core_access_t *pm_core = &core->pm_core; 334 phymod_access_t *phyacc = &pm_core->access; 335 int pll = PHYMOD_ACC_PLLIDX(phyacc); 336 phy_ctrl_t *pc = EXT_PHY_SW_STATE(core->unit, core->port); 337 int pmd = (reg_addr & 0x08000000) ? 1 : 0; 338 int sys = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 1 : 0; 339 int tsc_port, lane_mode; 340 341 tsc_port = (sys << 3) + (pc->phy_id & 0x7) + 1; 342 lane_mode = (reg_addr >> 16) & 7; 343 344 rv = _tsc_reg_read(core->unit, pc, lane_mode, tsc_port, pmd, pll, (reg_addr & 0xffff), &data16); 345 346 *val = data16; 347 348 return rv; 349 } 350 351 /* 352 * Function: 353 * _8806x_reg_write 354 * Doc: 355 * register write operations 356 * Parameters: 357 * unit - (IN) unit number 358 * core_addr - (IN) core address 359 * reg_addr - (IN) address to write 360 * val - (IN) write value 361 */ 362 STATIC int 363 _8806x_reg_write(void* user_acc, uint32_t core_addr, uint32_t reg_addr, uint32_t val) 364 { 365 int rv = SOC_E_NONE; 366 soc_phymod_core_t *core = (soc_phymod_core_t *)user_acc; 367 phymod_core_access_t *pm_core = &core->pm_core; 368 phymod_access_t *phyacc = &pm_core->access; 369 int pll = PHYMOD_ACC_PLLIDX(phyacc); 370 phy_ctrl_t *pc = EXT_PHY_SW_STATE(core->unit, core->port); 371 int pmd = (reg_addr & 0x08000000) ? 1 : 0; 372 int sys = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 1 : 0; 373 int tsc_port, lane_mode; 374 uint16 value = val & 0xffff; 375 uint16 mask = (val & 0xffff0000) ? ((~val) >> 16) : (val >> 16); 376 377 tsc_port = (sys << 3) + (pc->phy_id & 0x7) + 1; 378 lane_mode = (reg_addr >> 16) & 7; 379 380 rv = _tsc_reg_write(core->unit, pc, lane_mode, tsc_port, pmd, pll, (reg_addr & 0xffff), value, mask); 381 382 return rv; 383 } 384 385 #define USE_PHY8806X_FW_STAT 386 387 int 388 _8806x_xmod_command(void *data) 389 { 390 xmod_buf_desc *bdp = (xmod_buf_desc *)data; 391 392 soc_phymod_core_t *soc_core; 393 394 if (bdp) { 395 soc_core = PHYMOD_ACC_USER_ACC(bdp->pa); 396 #ifdef USE_PHY8806X_FW_STAT 397 if (bdp->mode_opcode == XMOD_CMD_MODE_ETH(XMOD_PHY_INTERFACE_CONFIG_GET)) { 398 return(phy_8806x_fw_stat_read(soc_core->unit, soc_core->port, 399 FWSTAT_PHY_INTERFACE_CONFIG_GET_OFFSET, bdp->xmodrxbuff, bdp->xmodrxlen)); 400 } else if (bdp->mode_opcode == XMOD_CMD_MODE_ETH(XMOD_PHY_AUTONEG_GET)) { 401 return(phy_8806x_fw_stat_read(soc_core->unit, soc_core->port, 402 FWSTAT_PHY_AUTONEG_GET_OFFSET, bdp->xmodrxbuff, bdp->xmodrxlen)); 403 } else 404 #endif 405 if (bdp->mode_opcode == XMOD_CMD_MODE_ETH(XMOD_PHY_RX_PMD_LOCKED_GET)) { 406 return (phy8806x_tsc_pmd_lock_status (bdp->pa, (uint8_t *)bdp->xmodrxbuff)); 407 } else { 408 return (phy_8806x_xmod_command(soc_core->unit, soc_core->port, bdp->mode_opcode, 409 bdp->xmodtxbuff, bdp->xmodtxlen, bdp->xmodrxbuff, bdp->xmodrxlen)); 410 } 411 } 412 413 return SOC_E_UNAVAIL; 414 } 415 416 417 #define IS_DUAL_LANE_PORT(_pc) ((_pc)->phy_mode == PHYCTRL_DUAL_LANE_PORT) 418 #define IND_LANE_MODE(_pc) (((_pc)->phy_mode == PHYCTRL_DUAL_LANE_PORT) || ((_pc)->phy_mode == PHYCTRL_ONE_LANE_PORT)) 419 420 uint8 * phy8806x_eth_ctr_get(phy_ctrl_t *pc) 421 { 422 return ((uint8 *) ETH_CTR(pc)); 423 } 424 425 void phy8806x_led_tx_set(phy_ctrl_t *pc, uint8 val) 426 { 427 LED_TX(pc) = val; 428 return; 429 } 430 431 void phy8806x_led_rx_set(phy_ctrl_t *pc, uint8 val) 432 { 433 LED_RX(pc) = val; 434 return; 435 } 436 437 STATIC int 438 phy8806x_port_config_init(phy8806x_speed_config_t* speed_config, phymod_port_config_t *port_config) 439 { 440 port_config->interface = speed_config->interface; 441 port_config->sys_lane_count = speed_config->sys_lane_count; 442 port_config->ln_lane_count = speed_config->ln_lane_count; 443 port_config->an_mode= speed_config->an_mode; 444 port_config->an_cl72 = speed_config->an_cl72; 445 port_config->fs_cl72 = speed_config->fs_cl72; 446 port_config->fs_cl72_sys = speed_config->fs_cl72_sys; 447 port_config->an_fec = speed_config->an_fec; 448 port_config->speed = speed_config->speed; 449 port_config->port_is_higig = speed_config->port_is_higig; 450 port_config->an_fec = speed_config->an_fec; 451 port_config->port_mode = speed_config->port_mode; 452 port_config->fiber_pref = speed_config->fiber_pref; 453 port_config->fiber_pref_sys = speed_config->fiber_pref_sys; 454 port_config->fs_fec = speed_config->fs_fec; 455 port_config->fs_fec_sys = speed_config->fs_fec_sys; 456 port_config->is_flex = speed_config->is_flex; 457 port_config->quad_mode = speed_config->quad_mode; 458 459 return SOC_E_NONE; 460 } 461 462 /* 463 * Function: 464 * phy8806x_speed_to_interface_config_get 465 * Purpose: 466 * Convert speed to interface_config struct 467 * Parameters: 468 * unit - BCM unit number. 469 * port - Port number. 470 * speed - speed to convert 471 * interface_config - output interface config struct 472 * Returns: 473 * SOC_E_NONE 474 */ 475 STATIC int 476 phy8806x_speed_to_interface_config_get(phy8806x_speed_config_t* speed_config, phymod_phy_inf_config_t* interface_config, TXDRV_INXS_t* tx_index) 477 { 478 int port_is_higig; 479 int port_num_lanes; 480 int fiber_pref; 481 482 port_num_lanes = speed_config->ln_lane_count; 483 port_is_higig = speed_config->port_is_higig; 484 fiber_pref = speed_config->fiber_pref; 485 486 SOC_IF_ERROR_RETURN(phymod_phy_inf_config_t_init(interface_config)); 487 488 interface_config->interface_modes = 0; 489 interface_config->data_rate = speed_config->speed; 490 interface_config->pll_divider_req = speed_config->pll_divider_req ; 491 interface_config->device_aux_modes= NULL ; 492 493 *tx_index = TXDRV_DFT_INX; 494 495 if (port_is_higig) { 496 PHYMOD_INTF_MODES_HIGIG_SET(interface_config); 497 } 498 switch (speed_config->speed) { 499 case 1000: 500 if (fiber_pref) { 501 interface_config->interface_type = phymodInterface1000X; 502 *tx_index = TXDRV_SFI_INX; 503 } else { 504 interface_config->interface_type = phymodInterfaceSGMII; 505 } 506 break; 507 case 10000: 508 if (speed_config->line_interface & PHY8806X_IF_SFI) 509 interface_config->interface_type = phymodInterfaceSFI; 510 else if (speed_config->line_interface & PHY8806X_IF_SR) 511 interface_config->interface_type = phymodInterfaceSR; 512 else if (speed_config->line_interface & PHY8806X_IF_CR) 513 interface_config->interface_type = phymodInterfaceCR; 514 else { 515 if (speed_config->fs_cl72_sys) 516 interface_config->interface_type = phymodInterfaceCR; 517 else 518 interface_config->interface_type = phymodInterfaceXFI; 519 } 520 break; 521 case 20000: 522 if (port_num_lanes == 1) { 523 if (speed_config->fs_cl72_sys) 524 interface_config->interface_type = phymodInterfaceCR; 525 else 526 interface_config->interface_type = phymodInterfaceXFI; 527 528 *tx_index = TXDRV_XFI_INX; 529 } else if(port_num_lanes == 2) { 530 interface_config->interface_type = phymodInterfaceCR2; 531 } 532 break ; 533 case 25000: 534 if (speed_config->fs_cl72_sys) 535 interface_config->interface_type = phymodInterfaceCR; 536 else 537 interface_config->interface_type = phymodInterfaceXFI; 538 *tx_index = TXDRV_XFI_INX; 539 break ; 540 case 40000: 541 if(fiber_pref){ 542 PHYMOD_INTF_MODES_FIBER_SET(interface_config); 543 } 544 if (port_num_lanes == 4) { 545 interface_config->interface_type = phymodInterfaceCR4; 546 *tx_index = TXDRV_XLAUI_INX; 547 } else { 548 interface_config->interface_type = phymodInterfaceCR2; 549 *tx_index = TXDRV_XLAUI_INX; 550 } 551 break; 552 case 42000: 553 if (port_num_lanes == 4) { 554 interface_config->interface_type = phymodInterfaceCR4; 555 *tx_index = TXDRV_XLAUI_INX; 556 } else { 557 interface_config->interface_type = phymodInterfaceCR2; 558 *tx_index = TXDRV_XLAUI_INX; 559 } 560 break; 561 case 50000: 562 if(fiber_pref){ 563 PHYMOD_INTF_MODES_FIBER_SET(interface_config); 564 } 565 if (port_num_lanes == 4) { 566 interface_config->interface_type = phymodInterfaceCR4; 567 *tx_index = TXDRV_XLAUI_INX; 568 } else { 569 interface_config->interface_type = phymodInterfaceCR2; 570 *tx_index = TXDRV_XLAUI_INX; 571 } 572 break; 573 case 100000: 574 interface_config->interface_type = phymodInterfaceCR4; 575 *tx_index = TXDRV_XLAUI_INX; 576 break; 577 case 106000: 578 interface_config->interface_type = phymodInterfaceCR4; 579 *tx_index = TXDRV_XLAUI_INX; 580 break; 581 default: 582 return SOC_E_PARAM; 583 } 584 585 switch (speed_config->port_refclk_int) 586 { 587 case 156: 588 interface_config->ref_clock = phymodRefClk156Mhz; 589 break; 590 case 125: 591 interface_config->ref_clock = phymodRefClk125Mhz; 592 break; 593 default: 594 return SOC_E_PARAM; 595 } 596 return SOC_E_NONE; 597 } 598 599 STATIC int 600 phy8806x_phymod_interfacetype_to_soc_type (phymod_interface_t interface_type, soc_port_if_t *pif) 601 { 602 switch (interface_type) { 603 case phymodInterface1000X: 604 *pif = SOC_PORT_IF_GMII; 605 break; 606 case phymodInterfaceSGMII: 607 *pif = SOC_PORT_IF_SGMII; 608 break; 609 case phymodInterfaceXFI: 610 *pif = SOC_PORT_IF_XFI; 611 break; 612 case phymodInterfaceSFI: 613 *pif = SOC_PORT_IF_SFI; 614 break; 615 case phymodInterfaceXLAUI: 616 *pif = SOC_PORT_IF_XLAUI; 617 break; 618 case phymodInterfaceKX: 619 *pif = SOC_PORT_IF_KX; 620 break; 621 case phymodInterfaceRXAUI: 622 *pif = SOC_PORT_IF_RXAUI; 623 break; 624 case phymodInterfaceXGMII: 625 *pif = SOC_PORT_IF_XGMII; 626 break; 627 case phymodInterfaceKR2: 628 *pif = SOC_PORT_IF_KR2; 629 break; 630 case phymodInterfaceCR2: 631 *pif = SOC_PORT_IF_CR2; 632 break; 633 case phymodInterfaceSR2: 634 *pif = SOC_PORT_IF_SR2; 635 break; 636 case phymodInterfaceSR4: 637 *pif = SOC_PORT_IF_SR4; 638 break; 639 case phymodInterfaceCR4: 640 *pif = SOC_PORT_IF_CR4; 641 break; 642 case phymodInterfaceKR4: 643 *pif = SOC_PORT_IF_KR4; 644 break; 645 case phymodInterfaceCR: 646 *pif = SOC_PORT_IF_CR; 647 break; 648 case phymodInterfaceKR: 649 *pif = SOC_PORT_IF_KR; 650 break; 651 case phymodInterfaceSR: 652 *pif = SOC_PORT_IF_SR; 653 break; 654 case phymodInterfaceCR10: 655 *pif = SOC_PORT_IF_CAUI; 656 break; 657 case phymodInterfaceCAUI4: 658 *pif = SOC_PORT_IF_CAUI; 659 break; 660 case phymodInterfaceBypass: 661 *pif = SOC_PORT_IF_ILKN; 662 break; 663 default: 664 *pif = SOC_PORT_IF_XGMII; 665 break; 666 } 667 668 return 0; 669 } 670 671 /* 672 * Given the BMP port number, the function returns 673 * the Quad mode (single, Tri0, Tri1, Dual, Single mode. 674 */ 675 int get_quad_mode (int port) 676 { 677 int i = 0; 678 int unit = 0; 679 int port_idx = 0; 680 int lane_cnt = 0; 681 int quad_mode = 0; 682 683 while ((i < 4) && (port_idx < 4)) { 684 switch (port_idx) { 685 case 0: 686 lane_cnt = SOC_INFO(unit).port_num_lanes[port+port_idx]; 687 switch (lane_cnt) { 688 case 1: 689 quad_mode = _BFCMAPPER_PORT_MODE_QUAD; /* QUAD */ 690 break; 691 case 2: 692 quad_mode = _BFCMAPPER_PORT_MODE_DUAL; /* DUAL */ 693 break; 694 case 4: 695 quad_mode = _BFCMAPPER_PORT_MODE_SINGLE; /* SINGLE */ 696 return (quad_mode); 697 } 698 break; 699 case 2: 700 lane_cnt = SOC_INFO(unit).port_num_lanes[port+port_idx]; 701 switch (lane_cnt) { 702 case 1: 703 if (quad_mode == _BFCMAPPER_PORT_MODE_DUAL) 704 quad_mode = _BFCMAPPER_PORT_MODE_TRI_0023; /* TRI0 */ 705 break; 706 case 2: 707 if (quad_mode == _BFCMAPPER_PORT_MODE_QUAD) 708 quad_mode = _BFCMAPPER_PORT_MODE_TRI_0122; /* TRI1 */ 709 break; 710 711 } 712 } 713 714 port_idx += lane_cnt; 715 i++; 716 } 717 718 return quad_mode; 719 } 720 721 /* 722 * Given a port number, the function returns the BMP port numbrt. 723 */ 724 int get_bmp_port (int port, phy_ctrl_t *pc) 725 { 726 int unit = 0; 727 uint16 phy_addr=0; 728 729 phy_addr = pc->phy_id; 730 731 phy_addr -= phy_addr & 0x3; 732 port= PHY_ADDR_TO_PORT(unit, phy_addr); 733 734 return port; 735 } 736 737 int compute_quad_mode (int unit, int port) 738 { 739 phy_ctrl_t *pc; 740 int bmp_port; 741 742 pc = EXT_PHY_SW_STATE(unit, port); 743 bmp_port = get_bmp_port(port, pc); 744 return get_quad_mode(bmp_port); 745 } 746 747 /* 748 * Function: 749 * phy8806x_config_init 750 * Purpose: 751 * Determine phy configuration data for purposes of PHYMOD initialization. 752 * 753 * A side effect of this procedure is to save some per-logical port 754 * information in (phy8806x_cfg_t *) &pc->driver_data; 755 * 756 * Parameters: 757 * unit - BCM unit number. 758 * port - Port number. 759 * logical_lane_offset - starting logical lane number 760 * Returns: 761 * SOC_E_NONE 762 */ 763 STATIC int 764 phy8806x_config_init(int unit, soc_port_t port, int logical_lane_offset, 765 phymod_core_init_config_t *core_init_config, 766 phymod_phy_init_config_t *pm_phy_init_config) 767 { 768 phy_ctrl_t *pc; 769 phy8806x_speed_config_t *speed_config; 770 phy8806x_config_t *pCfg; 771 phymod_firmware_load_method_t fw_ld_method; 772 int port_refclk_int; 773 int port_num_lanes; 774 int core_num; 775 int phy_num_lanes; 776 int port_is_higig; 777 int phy_passthru; 778 int lane_map_rx, lane_map_tx, lane_map_tx_l=0; 779 int i; 780 int fiber_pref = 1; 781 TXDRV_INXS_t tx_index = TXDRV_DFT_INX; 782 uint32 temp32; 783 soc_port_if_t soc_if; 784 phy_ctrl_t *int_pc; 785 786 pc = EXT_PHY_SW_STATE(unit, port); 787 if (pc == NULL) { 788 return SOC_E_INTERNAL; 789 } 790 791 int_pc = INT_PHY_SW_STATE(unit, port); 792 if (int_pc == NULL) { 793 return SOC_E_INTERNAL; 794 } 795 796 pCfg = (phy8806x_config_t *) pc->driver_data; 797 798 /* extract data from SOC_INFO */ 799 /*port_refclk_int = SOC_INFO(unit).port_refclk_int[port];*/ 800 port_refclk_int = 156; 801 port_num_lanes = SOC_INFO(unit).port_num_lanes[port]; 802 port_is_higig = PBMP_MEMBER(PBMP_HG_ALL(unit), port); 803 804 /* figure out how many lanes are in this phy */ 805 core_num = (logical_lane_offset / 4); 806 phy_num_lanes = (port_num_lanes - logical_lane_offset); 807 if (phy_num_lanes > MAX_NUM_LANES) { 808 phy_num_lanes = MAX_NUM_LANES; 809 } 810 811 /* 812 CORE configuration 813 */ 814 phymod_core_init_config_t_init(core_init_config); 815 /* Set the core_mode to Ethernet. Need to add a config variable to get the right core Mode */ 816 #if defined(INCLUDE_FCMAP) 817 if (pc->fcmap_enable) { 818 /* Set Core Mode to FIBER_CHANNEL_MODE */ 819 core_init_config->core_mode = 1; 820 } else 821 #endif 822 { 823 /* Set Core Mode to ETHERNET_MODE */ 824 core_init_config->core_mode = 0; 825 } 826 fw_ld_method = phymodFirmwareLoadMethodNone; 827 828 core_init_config->firmware_load_method = soc_property_port_get(unit, port, 829 spn_LOAD_FIRMWARE, fw_ld_method); 830 core_init_config->firmware_load_method &= 0xff; /* clear checksum bits */ 831 core_init_config->lane_map.num_of_lanes = port_num_lanes; 832 833 /* Both internal data structure is logic lane base */ 834 lane_map_rx = soc_property_port_suffix_num_get(unit, port, core_num, 835 spn_PHY_RX_LANE_MAP, "core", 0x3210); 836 for (i=0; i<NUM_LANES; i++) { 837 core_init_config->lane_map.lane_map_rx[i] = (lane_map_rx >> (i * 4 /* 4 bit per lane */)) & 0xf; 838 } 839 840 lane_map_tx = soc_property_port_suffix_num_get(unit, port, core_num, 841 spn_PHY_TX_LANE_MAP, "core", 0x3210); 842 for (i=0; i<NUM_LANES; i++) { 843 lane_map_tx_l |= i << 4*((lane_map_tx >> (i*4)) & 0xf) ; 844 } 845 for (i=0; i<NUM_LANES; i++) { 846 core_init_config->lane_map.lane_map_tx[i] = (lane_map_tx_l >> (i * 4 /*4 bit per lane*/)) & 0xf; 847 } 848 849 /* next get the tx/rx polairty info */ 850 core_init_config->polarity_map.rx_polarity = soc_property_port_get(unit, port, spn_PHY_RX_POLARITY_FLIP, 0); 851 core_init_config->polarity_map.tx_polarity = soc_property_port_get(unit, port, spn_PHY_TX_POLARITY_FLIP, 0); 852 853 speed_config = &(pCfg->speed_config); 854 speed_config->port_refclk_int = port_refclk_int; 855 speed_config->speed = soc_property_port_get(unit, port, spn_PORT_INIT_SPEED, pc->speed_max); 856 speed_config->ln_lane_count = phy_num_lanes; 857 speed_config->port_is_higig = port_is_higig; 858 speed_config->line_interface = soc_property_port_get(unit, port, spn_SERDES_IF_TYPE, SOC_PORT_IF_CR); 859 speed_config->fiber_pref = soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 0); 860 speed_config->fiber_pref_sys = soc_property_port_get(unit, port, spn_SERDES_FIBER_PREF, 0); 861 speed_config->port_mode = soc_property_port_get(unit, port, spn_PHY_OPERATIONAL_MODE, 0); 862 speed_config->an_fec = soc_property_port_get(unit, port, spn_PHY_EXT_AN_FEC, 0); 863 speed_config->fs_cl72 = soc_property_port_get(unit, port, spn_PHY_INIT_CL72, 0); 864 speed_config->fs_cl72_sys = soc_property_port_get(unit, port, spn_PORT_INIT_CL72, 0); 865 speed_config->an_cl72 = soc_property_port_get(unit, port, spn_PHY_AN_C72, 1); 866 speed_config->fs_fec = soc_property_port_get(unit, port, spn_PHY_FEC_ENABLE, 0); 867 speed_config->fs_fec_sys = soc_property_port_get(unit, port, spn_SERDES_FEC_ENABLE, 0); 868 speed_config->an_mode = soc_property_port_get(unit, port, spn_PHY_AN_C73, 0); 869 speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE; 870 871 #ifdef BCM_TRIDENT2_SUPPORT 872 if ((FLAGS(pc) & PHY8806X_FLEX) && SOC_IS_TRIDENT2(unit)) { 873 if ((speed_config->ln_lane_count > 1) && ((speed_config->speed == 10000) || (speed_config->speed == 25000))) { 874 speed_config->speed = speed_config->ln_lane_count * speed_config->speed; 875 PHYCTRL_SPEED_SET(int_pc, int_pc->unit, int_pc->port, speed_config->speed); 876 } 877 878 if ((speed_config->ln_lane_count == 1) && ((speed_config->speed == 40000) || (speed_config->speed == 100000))) { 879 if (speed_config->ln_lane_count == 1) { 880 switch (speed_config->speed) { 881 case 40000: 882 case 42000: 883 case 100000: 884 case 106000: 885 speed_config->speed = speed_config->speed/4; 886 break; 887 case 20000: 888 case 50000: 889 speed_config->speed = speed_config->speed/2; 890 break; 891 default: 892 break; 893 } 894 PHYCTRL_SPEED_SET(int_pc, int_pc->unit, int_pc->port, speed_config->speed); 895 } 896 } 897 } 898 #endif 899 900 SOC_IF_ERROR_RETURN(soc_mac_probe(unit, port, &(speed_config->macd))); 901 902 if (speed_config->port_mode == ETH_REPEATER) { 903 PHY_FLAGS_SET(unit, port, PHY_FLAGS_REPEATER); 904 if (FLAGS(pc) & PHY8806X_BMP0) { 905 SOC_IF_ERROR_RETURN 906 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32)); 907 temp32 |= 1 << 2; 908 SOC_IF_ERROR_RETURN 909 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32)); 910 } 911 912 if (FLAGS(pc) & PHY8806X_BMP1) { 913 SOC_IF_ERROR_RETURN 914 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32)); 915 temp32 |= 1 << 3; 916 SOC_IF_ERROR_RETURN 917 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32)); 918 } 919 } 920 921 922 if (speed_config->port_mode == ETH_GEARBOX) { 923 speed_config->sys_lane_count = phy_num_lanes; 924 speed_config->ln_lane_count = GEARBOX_LINE_LANE_CNT; 925 } else { 926 speed_config->sys_lane_count = speed_config->ln_lane_count; 927 } 928 929 SOC_IF_ERROR_RETURN 930 (phy8806x_speed_to_interface_config_get(speed_config, &(core_init_config->interface), &tx_index)); 931 932 phy8806x_phymod_interfacetype_to_soc_type(core_init_config->interface.interface_type, &soc_if); 933 934 /* coverity[mixed_enums]: ignore */ 935 speed_config->interface = soc_if; 936 /* coverity[mixed_enums]: ignore */ 937 core_init_config->interface.interface_type = soc_if; 938 /* 939 PHY configuration 940 */ 941 942 phymod_phy_init_config_t_init(pm_phy_init_config); 943 944 945 pm_phy_init_config->cl72_en = soc_property_port_get(unit, port, spn_PHY_AN_C72, TRUE); 946 pm_phy_init_config->an_en = TRUE; 947 948 /* check the higig port mode, then set the default cl73 mode */ 949 if (port_is_higig) { 950 pCfg->cl73an = FALSE; 951 } else { 952 pCfg->cl73an = PHY8806X_CL73_W_BAM; 953 } 954 955 /* by default disable cl37 */ 956 pCfg->an_cl72 = TRUE; 957 pCfg->forced_init_cl72 = FALSE; 958 pCfg->an_fec = FALSE; 959 960 pCfg->cl73an = soc_property_port_get(unit, port, 961 spn_PHY_AN_C73, pCfg->cl73an); 962 pCfg->an_cl72 = soc_property_port_get(unit, port, 963 spn_PHY_AN_C72, pCfg->an_cl72); 964 pCfg->an_fec = soc_property_port_get(unit, port, 965 spn_PHY_EXT_AN_FEC, pCfg->an_fec); 966 967 pCfg->forced_init_cl72 = soc_property_port_get(unit, port, 968 spn_PHY_INIT_CL72, pCfg->forced_init_cl72); 969 970 971 /* 972 phy_ctrl_t configuration (LOGICAL PORT BASED) 973 Only do this once, for the first core of the logical port 974 */ 975 if (core_num == 0) { 976 977 978 /* phy_mode, PHYCTRL_MDIO_ADDR_SHARE, PHY_FLAGS_INDEPENDENT_LANE */ 979 if (port_num_lanes == 4) { 980 pc->phy_mode = PHYCTRL_QUAD_LANE_PORT; 981 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_INDEPENDENT_LANE); 982 } else if (port_num_lanes == 2) { 983 pc->phy_mode = PHYCTRL_DUAL_LANE_PORT; 984 pc->flags |= PHYCTRL_MDIO_ADDR_SHARE; 985 PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE); 986 } else if (port_num_lanes == 1) { 987 pc->phy_mode = PHYCTRL_ONE_LANE_PORT; 988 pc->flags |= PHYCTRL_MDIO_ADDR_SHARE; 989 PHY_FLAGS_SET(unit, port, PHY_FLAGS_INDEPENDENT_LANE); 990 } 991 992 /* PHY_FLAGS_PASSTHRU */ 993 phy_passthru = 0; 994 if (PHY_EXTERNAL_MODE(unit, port)) { 995 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU); 996 phy_passthru = soc_property_port_get(unit, port, 997 spn_PHY_PCS_REPEATER, 0); 998 if (phy_passthru) { 999 PHY_FLAGS_SET(unit, port, PHY_FLAGS_PASSTHRU); 1000 } 1001 } 1002 1003 /* PHY_FLAGS_FIBER */ 1004 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER); 1005 if (fiber_pref) { 1006 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER); 1007 } 1008 } 1009 1010 return SOC_E_NONE; 1011 } 1012 1013 /* 1014 * Function: 1015 * phy_8806x_init 1016 * 1017 * An SDK "phy" is a logical port, which can consist of from 1-10 lanes, 1018 * (A phy with more than 4 lanes requires more than one core). 1019 * Per-logical port information is saved in (phy8806x_cfg_t *) &pc->driver_data. 1020 * An SDK phy is implemented as one or more PHYMOD "phy"s. 1021 * 1022 * A PHYMOD "phy" resides completely within a single core, which can be 1023 * from 1 to 4 lanes. 1024 * Per-phymod phy information is kept in (soc_phymod_ctrl_t) *pc->phymod_ctrl 1025 * A phymod phy points to its core. Up to 4 phymod phys can be on a single core 1026 * 1027 * Purpose: 1028 * Initialize a phy8806x phy 1029 * Parameters: 1030 * unit - BCM unit number. 1031 * port - Port number. 1032 * Returns: 1033 * SOC_E_NONE 1034 */ 1035 STATIC int 1036 phy_8806x_init(int unit, soc_port_t port) 1037 { 1038 phy_ctrl_t *pc; 1039 soc_phymod_ctrl_t *pmc = NULL; 1040 soc_phymod_phy_t *phy = NULL; 1041 soc_phymod_core_t *core = NULL; 1042 phy8806x_config_t *pCfg = NULL; 1043 phy8806x_speed_config_t *speed_config = NULL; 1044 /* soc_phy_info_t *pi = NULL; */ 1045 phymod_phy_inf_config_t interface_config; 1046 phymod_core_status_t core_status; 1047 phymod_core_info_t core_info; 1048 int idx, rv = SOC_E_NONE; 1049 int logical_lane_offset; 1050 soc_port_ability_t ability; 1051 TXDRV_INXS_t tx_index = TXDRV_DFT_INX; 1052 phymod_port_config_t port_config; 1053 uint32 temp32; 1054 uint16 temp16; 1055 uint8 *fw = NULL; 1056 int fw_len = 0; 1057 int bm, cm; 1058 int bmp_port = 0; 1059 int fwdlm; 1060 uint16 status_l = 0, status_s = 0; 1061 soc_port_if_t soc_if; 1062 int port_is_higig, port_was_higig; 1063 1064 pc = EXT_PHY_SW_STATE(unit, port); 1065 if (pc == NULL) { 1066 return SOC_E_INTERNAL; 1067 } 1068 LOG_INFO(BSL_LS_SOC_PHY, (BSL_META_U(unit, 1069 "u=%d p=%d PHYCTRL_INIT_STATE = %u speed_max = %d - %s\n"), 1070 unit, pc->port, PHYCTRL_INIT_STATE(pc), pc->speed_max, 1071 (FLAGS(pc) & PHY8806X_FLEX) ? "FLEX" : "REGULAR" )); 1072 1073 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) || 1074 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1075 1076 pc->driver_data = (void*)(pc+1); 1077 pmc = &pc->phymod_ctrl; 1078 pCfg = (phy8806x_config_t *) pc->driver_data; 1079 1080 port_is_higig = PBMP_MEMBER(PBMP_HG_ALL(unit), port); 1081 /* Extract previous higig status before we clear the structure. 1082 This is possible because the SDK reuses the previous phyctrl. 1083 */ 1084 port_was_higig = pCfg->speed_config.port_is_higig; 1085 1086 sal_memset(pCfg, 0, sizeof(*pCfg)); 1087 speed_config = &(pCfg->speed_config); 1088 1089 sal_memset(&ability, 0, sizeof(ability)); 1090 1091 if (xmod_mutex[unit] == NULL) { 1092 xmod_mutex[unit] = sal_mutex_create("xmod_mutex"); 1093 } 1094 1095 if (xmod_mutex[unit] == NULL) { 1096 return SOC_E_MEMORY; 1097 } 1098 1099 SOC_IF_ERROR_RETURN 1100 (READ_TOP_DEV_REV_ID_REG(unit, pc, &TOP_DEV_REV_ID(pc))); 1101 1102 LED_TX(pc) = 0; 1103 LED_RX(pc) = 0; 1104 LED_SPEED(pc) = 0; 1105 FLAGS(pc) = 0; 1106 PHY_FLAGS_SET(unit, port, PHY_FLAGS_C45); 1107 1108 /* Use the following config variable for now until a new one is approved. */ 1109 if (soc_property_port_get(unit, port,spn_PHY_FORCE_FIRMWARE_LOAD, FALSE)) { 1110 FLAGS(pc) |= PHY8806X_PM; 1111 } 1112 1113 #ifdef PORTMOD_SUPPORT 1114 if (soc_feature(unit, soc_feature_portmod)) { 1115 FLAGS(pc) |= PHY8806X_PORTMOD; 1116 } 1117 #endif 1118 1119 if ((SOC_CONTROL(unit)->soc_flags & SOC_F_ALL_MODULES_INITED) && (!port_is_higig != !port_was_higig)) { 1120 FLAGS(pc) |= PHY8806X_ENCAP_CHANGE; 1121 } 1122 1123 if (soc_phy_boot_master_get(unit, port, &bm, &cm) == SOC_E_NONE) { 1124 if (bm) { 1125 if ((pc->phy_id & 0x4) == 0x0) { 1126 FLAGS(pc) |= PHY8806X_BMP0; 1127 } else { 1128 FLAGS(pc) |= PHY8806X_BMP1; 1129 } 1130 if (cm) { 1131 FLAGS(pc) |= PHY8806X_CHM; 1132 } 1133 } 1134 } else { 1135 if ((pc->phy_id & 0x7) == 0x0) { 1136 FLAGS(pc) |= PHY8806X_BMP0; 1137 FLAGS(pc) |= PHY8806X_CHM; 1138 } else if ((pc->phy_id & 0x7) == 0x4) { 1139 FLAGS(pc) |= PHY8806X_BMP1; 1140 } 1141 } 1142 1143 if ((fwdlm = soc_property_port_get(unit, port,spn_MDIO_FIRMWARE_DOWNLOAD_MASTER, 0)) == -1) { 1144 if (FLAGS(pc) & PHY8806X_CHM) { 1145 FLAGS(pc) |= PHY8806X_AC; 1146 } 1147 } else if (fwdlm == -2) { 1148 if (FLAGS(pc) & PHY8806X_CHM) { 1149 FLAGS(pc) |= PHY8806X_FWDLM; 1150 } 1151 } else if (fwdlm == pc->port) { 1152 FLAGS(pc) |= PHY8806X_FWDLM; 1153 } 1154 1155 if (!(SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit))) { 1156 1157 temp32 = 0; 1158 1159 /* Initialize the uart_ptr via AXI memory of the mHost (pc->phy_id & 0x3) before f/w starts to avoid a race condition. */ 1160 SOC_IF_ERROR_RETURN 1161 (_phy_8806x_axi_write(unit, pc, 0x27fff8 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1)); 1162 1163 /* Initialize the print_ptr via AXI memory of the mHost (pc->phy_id & 0x3) before f/w starts to avoid a race condition. */ 1164 SOC_IF_ERROR_RETURN 1165 (_phy_8806x_axi_write(unit, pc, 0x27fffc + (pc->phy_id & 0x3) * 0x100000, &temp32, 1)); 1166 1167 1168 temp32 = soc_property_port_get(unit, port, spn_PHY_DIAG_BMP, 1); 1169 if (temp32 & 0x4) { 1170 FLAGS(pc) |= PHY8806X_FW_RESTART; 1171 } 1172 temp32 = HOST2LE32(temp32 & 0xffff03); 1173 1174 /* Initialize the mode via AXI memory of the mHost (pc->phy_id & 0x3) */ 1175 SOC_IF_ERROR_RETURN 1176 (_phy_8806x_axi_write(unit, pc, 0x27fff4 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1)); 1177 1178 } 1179 1180 #if defined(INCLUDE_FCMAP) 1181 pc->fcmap_enable = soc_property_port_get(unit, port, spn_FCMAP_ENABLE, 0); 1182 1183 if (pc->fcmap_enable && !(PHY_IS_BCM88060(pc) || PHY_IS_BCM88061(pc))) { 1184 LOG_ERROR(BSL_LS_SOC_PHY, 1185 (BSL_META_U(unit, 1186 "u=%d p=%d FC not supported on the device !.\n"), unit, port)); 1187 pc->fcmap_enable = 0; 1188 } 1189 1190 pc->fcmap_dev_port = 0; 1191 pc->fcmap_uc_dev_addr = SOC_FCMAPPHY_MDIO_ADDR(unit, pc->phy_id, 1); 1192 pc->fcmap_dev_addr = SOC_FCMAPPHY_MDIO_ADDR(unit, pc->phy_id, 1); 1193 1194 LOG_ERROR(BSL_LS_SOC_PHY, 1195 (BSL_META_U(unit, 1196 "FCMAP ENABLE %d, port %d, dev_addr 0x%x\n"), 1197 pc->fcmap_enable, port, pc->fcmap_dev_addr )); 1198 1199 #endif 1200 1201 if (SOC_CONTROL(unit)->soc_flags & SOC_F_ALL_MODULES_INITED) { 1202 SOC_IF_ERROR_RETURN 1203 (_phy_8806x_axi_read(unit, pc, 0x00100008, &temp32, 1)); 1204 temp32 = LE2HOST32(temp32); 1205 if (temp32 == 0x2032544d) { /* 'MT2 ' converted to uint32 LE = ((' '<< 24) + ('2'<< 16) + ('T'<< 8) + ('M'<< 0)) */ 1206 1207 #if defined(INCLUDE_FCMAP) 1208 SOC_IF_ERROR_RETURN 1209 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32)); 1210 1211 /* Mask out the other quad's bit. */ 1212 temp32 = (pc->phy_id & 0x4) ? (temp32 & (1 << 1)) : (temp32 & (1 << 0)); 1213 1214 if ((pc->fcmap_enable && (!temp32)) || ((!pc->fcmap_enable) && temp32)) { 1215 FLAGS(pc) |= PHY8806X_MODE_CHANGE; 1216 } else 1217 #endif 1218 { 1219 if (!(FLAGS(pc) & PHY8806X_ENCAP_CHANGE)) { 1220 FLAGS(pc) |= PHY8806X_FLEX; 1221 } 1222 } 1223 } else { 1224 FLAGS(pc) &= ~PHY8806X_FW_RESTART; 1225 } 1226 } 1227 1228 /* To skip restart */ 1229 if (FLAGS(pc) & PHY8806X_ENCAP_CHANGE) { 1230 goto PASS5_BOOT; 1231 } 1232 1233 if ( ((FLAGS(pc) & (PHY8806X_FLEX | PHY8806X_ENCAP_CHANGE))) && 1234 (!(SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit))) ){ 1235 /* determine the number of lanes */ 1236 int num_lanes = SOC_INFO(unit).port_num_lanes[port]; 1237 int starting_lane_index = pc->phy_id & 0x7; 1238 /* TOP_SOFT_RESET Register Bits 6-9 is for RTS0 and bits 10-13 is for RTS1. 1239 One bit per lane. Create a RMW mask for this register from the phy id and 1240 number of lanes, as per the following formula 1241 ((2**num_lanes) - 1) << (starting_lane_index + 6) (ANDed with Oxf = 4 bits) 1242 */ 1243 uint32 single_mask = (((1U << num_lanes) - 1) & 0xf) << (starting_lane_index + 6); 1244 /* TOP_RTS_MISC_CTRL Register Bits 0-7 is for RTS0 and bits 8-15 is for RTS1. 1245 Two bits per lane. Create a RMW mask for this register from the phy id and 1246 number of lanes, as per the following formula 1247 ((2**(2*num_lanes)) - 1) << (2*starting_lane_index) (ANDed with 0xff = 8 bits) 1248 */ 1249 uint32 dual_mask = (((1U << (num_lanes << 1)) - 1) & 0xff) << (starting_lane_index << 1); 1250 1251 /* LOG_CLI((BSL_META_U(unit, 1252 "u=%d p=%d single_mask = 0x%08x dual_mask = 0x%08x\n"), 1253 unit, pc->port, single_mask, dual_mask )); 1254 */ 1255 1256 /* Place mHosts of the lane in reset */ 1257 SOC_IF_ERROR_RETURN 1258 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 1259 temp32 |= single_mask; 1260 SOC_IF_ERROR_RETURN 1261 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 1262 1263 /* Halt the mHosts of the lane */ 1264 SOC_IF_ERROR_RETURN 1265 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32)); 1266 temp32 &= ~dual_mask; 1267 SOC_IF_ERROR_RETURN 1268 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32)); 1269 1270 /* Bring mHosts of the lane out of reset */ 1271 SOC_IF_ERROR_RETURN 1272 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 1273 temp32 &= ~single_mask; 1274 SOC_IF_ERROR_RETURN 1275 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 1276 1277 /* if (FLAGS(pc) & PHY8806X_ENCAP_CHANGE) { 1278 goto PASS4_BOOT; 1279 } 1280 */ 1281 /* jump to 4-th pass */ 1282 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS4); 1283 return SOC_E_NONE; 1284 } 1285 1286 1287 #ifdef BCM_WARM_BOOT_SUPPORT 1288 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)){ 1289 /* jump to 5-th pass */ 1290 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS5); 1291 return SOC_E_NONE; 1292 } 1293 #endif 1294 1295 FIRMWARE(pc) = bcm_8806x_firmware; 1296 FIRMWARE_LEN(pc) = bcm_8806x_firmware_size; 1297 pc->flags |= PHYCTRL_MDIO_BCST; 1298 pc->dev_name = dev_name_8806x; 1299 1300 /* Now check whether a newer version of firmware is available for this model */ 1301 rv = soc_phy_fw_get(pc->dev_name, &fw, &fw_len); 1302 if (SOC_SUCCESS(rv)) { 1303 FIRMWARE(pc) = fw; 1304 FIRMWARE_LEN(pc) = fw_len; 1305 } 1306 1307 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS1) { 1308 /* initiate second pass of init if needed */ 1309 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS2); 1310 return SOC_E_NONE; 1311 } 1312 1313 } 1314 1315 /* Firmware download happens between PASS1 and PASS2 */ 1316 1317 1318 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) || 1319 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1320 1321 /* The BMPs should be ready to accept commands at this point 1322 and the others are in halt. */ 1323 /* Issue xmod_core_init(). (BMPs) */ 1324 if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) { 1325 do { 1326 1327 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03d, &status_l); 1328 if (SOC_FAILURE(rv)) { 1329 break; 1330 } 1331 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03d, &status_s); 1332 if (SOC_FAILURE(rv)) { 1333 break; 1334 } 1335 if ((status_l== 0x80) && (status_s == 0x80)) { 1336 break; 1337 } 1338 } while (!soc_timeout_check(&TO(pc))); 1339 1340 if ( status_l != 0x80 ) { 1341 LOG_CLI((BSL_META_U(unit, 1342 "PHY8806X PMD (line) firmware failed to compute CRC: u=%d p=%d status=%04x" 1343 " !.\n"), unit, pc->port, status_l)); 1344 } else { 1345 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03e, &temp16); 1346 if (SOC_FAILURE(rv) || (temp16 != PMD_CRC(pc))) { 1347 LOG_CLI((BSL_META_U(unit, 1348 "PHY8806X PMD (line) firmware CRC failure: u=%d p=%d expected=0x%04x computed=0x%04x" 1349 " !.\n"), unit, pc->port, PMD_CRC(pc), temp16)); 1350 } else { 1351 LOG_CLI((BSL_META_U(unit, 1352 "PHY8806X PMD (line) firmware CRC Ok: u=%d p=%d computed=0x%04x" 1353 " !.\n"), unit, pc->port, temp16)); 1354 } 1355 } 1356 1357 if ( status_s != 0x80 ) { 1358 LOG_CLI((BSL_META_U(unit, 1359 "PHY8806X PMD (sys) firmware failed to compute CRC: u=%d p=%d status=%04x" 1360 " !.\n"), unit, pc->port, status_s)); 1361 } else { 1362 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03e, &temp16); 1363 if (SOC_FAILURE(rv) || (temp16 != PMD_CRC(pc))) { 1364 LOG_CLI((BSL_META_U(unit, 1365 "PHY8806X PMD (sys) firmware CRC failure: u=%d p=%d expected=0x%04x computed=0x%04x" 1366 " !.\n"), unit, pc->port, PMD_CRC(pc), temp16)); 1367 } else { 1368 LOG_CLI((BSL_META_U(unit, 1369 "PHY8806X PMD (sys) firmware CRC Ok: u=%d p=%d computed=0x%04x" 1370 " !.\n"), unit, pc->port, temp16)); 1371 } 1372 } 1373 } 1374 1375 if ( FLAGS(pc) & PHY8806X_PM ) { 1376 return SOC_E_NONE; 1377 } 1378 1379 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS2) { 1380 /* initiate third pass of init if needed */ 1381 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS3); 1382 return SOC_E_NONE; 1383 } 1384 } 1385 1386 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS3) || 1387 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1388 1389 if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) { 1390 /* Get results of xmod_core_init(). (BMPs) */ 1391 1392 } 1393 1394 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS3) { 1395 /* initiate fourth pass of init if needed */ 1396 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS4); 1397 return SOC_E_NONE; 1398 } 1399 } 1400 1401 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS4) || 1402 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1403 1404 /* Enable FC Mode for Quad 0 */ 1405 if ((FLAGS(pc) & PHY8806X_BMP0)) { 1406 SOC_IF_ERROR_RETURN 1407 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32)); 1408 #if defined(INCLUDE_FCMAP) 1409 if (pc->fcmap_enable) { 1410 temp32 |= 1 << 0; 1411 } else { 1412 temp32 &= ~(1 << 0); 1413 } 1414 #else 1415 temp32 &= ~(1 << 0); 1416 #endif 1417 SOC_IF_ERROR_RETURN 1418 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32)); 1419 } 1420 1421 /* Enable FC Mode for Quad 1 */ 1422 if ((FLAGS(pc) & PHY8806X_BMP1)) { 1423 SOC_IF_ERROR_RETURN 1424 (READ_TOP_FC_MODE_CONTROL_REG(unit, pc, &temp32)); 1425 #if defined(INCLUDE_FCMAP) 1426 if (pc->fcmap_enable) { 1427 temp32 |= 1 << 1; 1428 } else { 1429 temp32 &= ~(1 << 1); 1430 } 1431 #else 1432 temp32 &= ~(1 << 1); 1433 #endif 1434 SOC_IF_ERROR_RETURN 1435 (WRITE_TOP_FC_MODE_CONTROL_REG(unit, pc, temp32)); 1436 } 1437 /* 1438 PASS4_BOOT: 1439 */ 1440 /* Start all non BMPs */ 1441 if (( FLAGS(pc) & (PHY8806X_FLEX | PHY8806X_ENCAP_CHANGE)) || 1442 ( !( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1)) )) { 1443 1444 SOC_IF_ERROR_RETURN 1445 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 1446 temp32 |= 1 << ((pc->phy_id & 0x7) + 6); 1447 SOC_IF_ERROR_RETURN 1448 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 1449 1450 SOC_IF_ERROR_RETURN 1451 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32)); 1452 temp32 &= ~(0x3 << ((pc->phy_id & 0x7) << 1)); 1453 temp32 |= (0x2 << ((pc->phy_id & 0x7) << 1)); 1454 SOC_IF_ERROR_RETURN 1455 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32)); 1456 1457 SOC_IF_ERROR_RETURN 1458 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 1459 temp32 &= ~(1 << ((pc->phy_id & 0x7) + 6)); 1460 SOC_IF_ERROR_RETURN 1461 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 1462 1463 } 1464 1465 if (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS4) { 1466 /* initiate fourth pass of init if needed */ 1467 PHYCTRL_INIT_STATE_SET(pc,PHYCTRL_INIT_STATE_PASS5); 1468 return SOC_E_NONE; 1469 } 1470 } 1471 1472 if ((PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_PASS5) || 1473 (PHYCTRL_INIT_STATE(pc) == PHYCTRL_INIT_STATE_DEFAULT)) { 1474 1475 /* don't restart */ 1476 PASS5_BOOT: 1477 pc = EXT_PHY_SW_STATE(unit, port); 1478 pc->driver_data = (void*)(pc+1); 1479 pmc = &pc->phymod_ctrl; 1480 pCfg = (phy8806x_config_t *) pc->driver_data; 1481 speed_config = &(pCfg->speed_config); 1482 1483 /* Loop through all phymod phys that support this SDK phy */ 1484 logical_lane_offset = 0; 1485 for (idx = 0; idx < pmc->num_phys; idx++) { 1486 phy = pmc->phy[idx]; 1487 core = phy->core; 1488 /* determine configuration data structure to default values, based on SOC properties */ 1489 SOC_IF_ERROR_RETURN 1490 (phy8806x_config_init(unit, port, 1491 logical_lane_offset, 1492 &core->init_config, &phy->init_config)); 1493 1494 1495 if (!core->init) { 1496 core_status.pmd_active = 0; 1497 core->init_config.trcvr_host_managed = soc_property_port_get(unit, port, spn_FCMAP_TRANSCEIVER_HOST_MANAGED, 0); 1498 SOC_IF_ERROR_RETURN 1499 (phymod_core_init(&core->pm_core, &core->init_config, &core_status)); 1500 core->init = TRUE; 1501 } 1502 1503 /*read serdes id info */ 1504 SOC_IF_ERROR_RETURN 1505 (phymod_core_info_get(&core->pm_core, &core_info)); 1506 1507 1508 /* for multicore phys, need to ratchet up to the next batch of lanes */ 1509 logical_lane_offset += core->init_config.lane_map.num_of_lanes; 1510 } 1511 1512 /* retrieve chip level information for serdes driver info */ 1513 /* pi = &SOC_PHY_INFO(unit, port); */ 1514 1515 1516 /* set the port to its max or init_speed */ 1517 SOC_IF_ERROR_RETURN 1518 (phy8806x_speed_to_interface_config_get(speed_config, &interface_config, &tx_index)); 1519 1520 phy8806x_phymod_interfacetype_to_soc_type(interface_config.interface_type, &soc_if); 1521 1522 speed_config->interface = soc_if; 1523 1524 phy8806x_port_config_init(speed_config, &port_config); 1525 1526 if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) { 1527 port_config.is_bootmaster = 1; 1528 } else { 1529 port_config.is_bootmaster = 0; 1530 } 1531 1532 /* Pass flex flag for both ETH and FC modes */ 1533 if (FLAGS(pc) & PHY8806X_FLEX) { 1534 port_config.is_flex = 1; 1535 } 1536 1537 /* Port Init for ETH only */ 1538 if (core->init_config.core_mode == 0) { 1539 bmp_port = get_bmp_port(port, pc); 1540 port_config.quad_mode = get_quad_mode(bmp_port); 1541 1542 SOC_IF_ERROR_RETURN 1543 (phymod_port_init(&phy->pm_phy, &port_config)); 1544 } 1545 1546 #if defined(INCLUDE_FCMAP) 1547 if (pc->fcmap_enable) { 1548 pc->fcmap_port_cfg = (void*)&port_config; 1549 rv = soc_fcmapphy_init(unit, port, pc, 1550 BFCMAP_CORE_BCM88060_A0, NULL); 1551 1552 if (!SOC_SUCCESS(rv)) { 1553 LOG_ERROR(BSL_LS_SOC_PHY, 1554 (BSL_META_U(unit, 1555 "soc_fcmapphy_init: FCMAP init for" 1556 " u=%d p=%d FAILED\n "), unit, port)); 1557 } else { 1558 LOG_INFO(BSL_LS_SOC_PHY, 1559 (BSL_META_U(unit, 1560 "soc_fcmapphy_init: FCMAP init for" 1561 " u=%d p=%d SUCCESS\n"), unit, port)); 1562 } 1563 return (rv); 1564 } 1565 #endif 1566 1567 /*next check if cl72 needs to be enabled */ 1568 if (pCfg->forced_init_cl72) { 1569 SOC_IF_ERROR_RETURN 1570 (phy8806x_cl72_enable_set(pmc, 1)); 1571 } 1572 1573 /* setup the port's an cap */ 1574 SOC_IF_ERROR_RETURN 1575 (phy_8806x_ability_local_get(unit, port, &ability)); 1576 1577 ability.medium = SOC_PA_MEDIUM_COPPER; 1578 ability.channel = SOC_PA_CHANNEL_LONG; 1579 ability.fec = SOC_PA_FEC_NONE; 1580 1581 SOC_IF_ERROR_RETURN 1582 (phy_8806x_ability_advert_set(unit, port, &ability)); 1583 1584 } 1585 LOG_INFO(BSL_LS_SOC_PHY, 1586 (BSL_META_U(pc->unit, 1587 "phy_8806x_init: u=%d p=%d\n"), unit, port)); 1588 1589 pc->fiber.enable = TRUE; 1590 pc->fiber.force_duplex = TRUE; 1591 pc->fiber.preferred = TRUE; 1592 1593 return SOC_E_NONE; 1594 } 1595 1596 /* 1597 * Function: 1598 * phy_8806x_link_get 1599 * Purpose: 1600 * Get layer2 connection status. 1601 * Parameters: 1602 * unit - BCM unit number. 1603 * port - Port number. 1604 * link - address of memory to store link up/down state. 1605 * Returns: 1606 * SOC_E_NONE 1607 */ 1608 STATIC int 1609 phy_8806x_link_get(int unit, soc_port_t port, int *link) 1610 { 1611 phy_ctrl_t *pc; 1612 int rv = SOC_E_NONE; 1613 uint16 link_st; 1614 int an = 0; 1615 int an_done = 0; 1616 phy8806x_config_t *pCfg; 1617 phy8806x_speed_config_t *speed_config; 1618 phy_ctrl_t *int_pc = NULL; 1619 phymod_phy_inf_config_t interface_config; 1620 phymod_ref_clk_t ref_clock; 1621 int speed, flag = 0; 1622 soc_phymod_phy_t *phy; 1623 soc_phymod_ctrl_t *pmc; 1624 phymod_autoneg_control_t an_control; 1625 int an_complete; 1626 phymod_phy_access_t *pm_phy; 1627 int local_fault = 0; 1628 int remote_fault = 0; 1629 static uint32_t trials=0; 1630 int fec_val=0; 1631 1632 *link = 0; 1633 /* locate phy control */ 1634 pc = EXT_PHY_SW_STATE(unit, port); 1635 if (pc == NULL) { 1636 return SOC_E_INTERNAL; 1637 } 1638 1639 pmc = &pc->phymod_ctrl; 1640 pCfg = (phy8806x_config_t *) pc->driver_data; 1641 speed_config = &(pCfg->speed_config); 1642 1643 #if defined(INCLUDE_FCMAP) 1644 if (pc->fcmap_enable) { 1645 rv = READ_FC_LINK_STATUS_REG(unit, pc, &link_st); 1646 *link = (link_st & VS_MISC_STATUS_LL_STATUS_BIT_MASK) ? TRUE: FALSE; 1647 return(rv); 1648 } 1649 #endif 1650 1651 int_pc = INT_PHY_SW_STATE(unit, port); 1652 if (int_pc == NULL) { 1653 return SOC_E_INTERNAL; 1654 } 1655 1656 SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, link)); 1657 if ((speed_config->repeater_an_phase == REPEATER_AN_PHASE_2) && (!*link)) { 1658 speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE; 1659 speed_config->repeater_an_resolved_speed = 0; 1660 speed_config->repeater_an_retry_phase0 = 0; 1661 phy_8806x_an_set(0, port, 0); 1662 phy_8806x_an_set(0, port, 1); 1663 return(SOC_E_NONE); 1664 } 1665 1666 if (speed_config->port_mode != ETH_REPEATER) { 1667 SOC_IF_ERROR_RETURN 1668 (phy_8806x_an_get(unit, port, &an, &an_done)); 1669 1670 if ( an ) { 1671 if ( !an_done ) { 1672 #if 0 1673 LOG_CLI((BSL_META_U(unit, 1674 "phy_8806x_link_get: AN not done, return \n"))); 1675 #endif 1676 *link = 0; 1677 return(SOC_E_NONE); 1678 } 1679 } 1680 1681 rv = READ_LINK_STATUS_REG(unit, pc, &link_st); 1682 *link = (link_st & VS_MISC_STATUS_LL_STATUS_BIT_MASK) >> 3; 1683 } else if (speed_config->port_mode == ETH_REPEATER) { 1684 if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) { 1685 /* We are in forced speed repeater mode. */ 1686 1687 local_fault = 0; 1688 remote_fault = 0; 1689 /* For now, only implemented for Tomohawk. Expand as needed */ 1690 #ifdef BCM_TOMAHAWK_SUPPORT 1691 if (SOC_IS_TOMAHAWK(unit)) { 1692 /* Read the FAULT if any */ 1693 if (speed_config->macd) { 1694 rv = MAC_CONTROL_GET(speed_config->macd, unit, port, SOC_MAC_CONTROL_FAULT_LOCAL_STATUS, &local_fault); 1695 rv = MAC_CONTROL_GET(speed_config->macd, unit, port, SOC_MAC_CONTROL_FAULT_REMOTE_STATUS, &remote_fault); 1696 } 1697 } 1698 #endif 1699 1700 #ifdef PORTMOD_SUPPORT 1701 if (FLAGS(pc) & PHY8806X_PORTMOD) { 1702 portmod_port_local_fault_status_get(unit, port, &local_fault); 1703 portmod_port_remote_fault_status_get(unit, port, &remote_fault); 1704 } 1705 #endif 1706 /* read the switch internal PHY link status (PCS link) */ 1707 SOC_IF_ERROR_RETURN(PHY_LINK_GET(int_pc->pd, unit, port, link)); 1708 1709 #ifdef PORTMOD_SUPPORT 1710 if (FLAGS(pc) & PHY8806X_PORTMOD) 1711 portmod_port_link_get(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, link); 1712 #endif 1713 1714 pm_phy = &pmc->phy[0]->pm_phy; 1715 1716 /* 1717 * JIRA SDK-118465 1718 * Reset the MT2 sys and line side if any one of the below conditions are met : 1719 * (a) If the switch internal PHY PCS link is DOWN. 1720 * (b) If the switch internal PHY PCS link is UP but the MAC is seeing LOCAL or REMOTE fault. 1721 */ 1722 if (!(*link) || 1723 ((*link) && (local_fault || remote_fault) && (speed_config->speed != 1000))) { 1724 trials++; 1725 /* Wait for the link to stabilize during device init. */ 1726 if (trials >= REPEATER_FS_RESET_TRIAL) { 1727 /* Send XMOD to reset the system and line side interface of MT2 port */ 1728 SOC_IF_ERROR_RETURN(phymod_reset_interface(pm_phy)); 1729 trials = 0; 1730 } 1731 } 1732 } else { 1733 /* Repeater AN mode is enabled. */ 1734 pm_phy = &pmc->phy[0]->pm_phy; 1735 SOC_IF_ERROR_RETURN 1736 (phymod_phy_autoneg_get(pm_phy, &an_control, (uint32_t *) &an_complete)); 1737 if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_0) { 1738 if (an_control.flags & REPEATER_AN_PHASE0_LOCKED) { 1739 if (REPEATER_AN_PHASE0_CL74 & an_control.flags) 1740 fec_val = 1; 1741 else 1742 fec_val = 0; 1743 1744 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION, fec_val); 1745 1746 speed_config->repeater_an_phase = REPEATER_AN_PHASE_1; 1747 1748 pmc = &pc->phymod_ctrl; 1749 phy = pmc->phy[0]; 1750 ref_clock = phymodRefClk156Mhz; 1751 /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */ 1752 SOC_IF_ERROR_RETURN(phymod_phy_interface_config_get(&phy->pm_phy, 1753 flag, ref_clock, &interface_config)); 1754 speed = interface_config.data_rate; 1755 speed_config->repeater_an_resolved_speed = interface_config.data_rate; 1756 1757 #ifdef PORTMOD_SUPPORT 1758 if ((FLAGS(pc) & PHY8806X_PORTMOD) && (interface_config.data_rate != 100000)) { 1759 if (REPEATER_AN_PHASE0_CL74 & an_control.flags) { 1760 fec_val = 1; 1761 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 1762 } 1763 } 1764 #endif 1765 1766 if (interface_config.data_rate == 100000) { 1767 speed_config->speed = interface_config.data_rate; 1768 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION, 0); 1769 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 1); 1770 #ifdef PORTMOD_SUPPORT 1771 if (FLAGS(pc) & PHY8806X_PORTMOD) { 1772 fec_val = 1; 1773 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 1774 PHYMOD_FEC_CL91_SET(fec_val); 1775 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 1776 } 1777 #endif 1778 } else { 1779 if (REPEATER_AN_PHASE0_CL91 & an_control.flags) { 1780 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 1); 1781 #ifdef PORTMOD_SUPPORT 1782 if (FLAGS(pc) & PHY8806X_PORTMOD) { 1783 fec_val = 1; 1784 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 1785 PHYMOD_FEC_CL91_SET(fec_val); 1786 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 1787 } 1788 #endif 1789 } else { 1790 /* CL91 is supported only for 100G */ 1791 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 0); 1792 #ifdef PORTMOD_SUPPORT 1793 if (FLAGS(pc) & PHY8806X_PORTMOD) { 1794 fec_val = 0; 1795 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 1796 PHYMOD_FEC_CL91_SET(fec_val); 1797 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 1798 } 1799 #endif 1800 } 1801 } 1802 1803 PHY_SPEED_SET(int_pc->pd, unit, port, speed); 1804 1805 /* Set for the next phase */ 1806 phy_8806x_an_set(0, port, 1); 1807 *link = 0; 1808 return(SOC_E_NONE); 1809 } else { 1810 *link = 0; 1811 if (speed_config->repeater_an_retry_phase0 >= REPEATER_AN_PHASE0_RETRY) { 1812 speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE; 1813 speed_config->repeater_an_resolved_speed = 0; 1814 phy_8806x_an_set(0, port, 0); 1815 phy_8806x_an_set(0, port, 1); 1816 speed_config->repeater_an_retry_phase0 = 0; 1817 } 1818 speed_config->repeater_an_retry_phase0++; 1819 return(SOC_E_NONE); 1820 } 1821 } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_1) { 1822 pm_phy = &pmc->phy[0]->pm_phy; 1823 SOC_IF_ERROR_RETURN 1824 (phymod_phy_autoneg_get(pm_phy, &an_control, (uint32_t *) &an_complete)); 1825 1826 if (an_control.flags & REPEATER_AN_PHASE1_LOCKED) { 1827 PHY_LINK_GET(int_pc->pd, unit, port, link); 1828 if (*link) { 1829 speed_config->repeater_an_phase = REPEATER_AN_PHASE_2; 1830 } 1831 } else { 1832 *link = 0; 1833 if (speed_config->repeater_an_retry_phase1 >= REPEATER_AN_PHASE1_RETRY) { 1834 speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE; 1835 speed_config->repeater_an_resolved_speed = 0; 1836 phy_8806x_an_set(0, port, 0); 1837 phy_8806x_an_set(0, port, 1); 1838 speed_config->repeater_an_retry_phase1 = 0; 1839 } 1840 speed_config->repeater_an_retry_phase1++; 1841 } 1842 return(SOC_E_NONE); 1843 } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_2) { 1844 PHY_LINK_GET(int_pc->pd, unit, port, link); 1845 return(SOC_E_NONE); 1846 } 1847 } 1848 return(SOC_E_NONE); 1849 } 1850 1851 return (rv); 1852 } 1853 1854 /* 1855 * Function: 1856 * phy_8806x_enable_set 1857 * Purpose: 1858 * Enable/Disable phy 1859 * Parameters: 1860 * unit - BCM unit number. 1861 * port - Port number. 1862 * enable - on/off state to set 1863 * Returns: 1864 * SOC_E_NONE 1865 */ 1866 STATIC int 1867 phy_8806x_enable_set(int unit, soc_port_t port, int enable) 1868 { 1869 phy_ctrl_t *pc; 1870 soc_phymod_ctrl_t *pmc; 1871 phymod_phy_access_t *pm_phy; 1872 1873 /* locate phy control */ 1874 pc = EXT_PHY_SW_STATE(unit, port); 1875 if (pc == NULL) { 1876 return SOC_E_INTERNAL; 1877 } 1878 1879 #if defined(INCLUDE_FCMAP) 1880 if (pc->fcmap_enable) { 1881 int p; 1882 int rv = SOC_E_NONE; 1883 1884 p = SOC_FCMAP_PORTID(unit, port); 1885 1886 /* If not enable, bring FC link down */ 1887 if (!enable) { 1888 LOG_ERROR(BSL_LS_SOC_PHY, 1889 (BSL_META_U(unit, 1890 "Bringing FC link down u=%d p=%d enable=%d rv=%d\n"), 1891 unit, port, enable, rv)); 1892 1893 rv = bfcmap_port_shutdown(p); 1894 } else { 1895 LOG_ERROR(BSL_LS_SOC_PHY, 1896 (BSL_META_U(unit, 1897 "Bringing FC link UP u=%d p=%d enable=%d rv=%d\n"), 1898 unit, port, enable, rv)); 1899 1900 rv = bfcmap_port_link_enable(p); 1901 } 1902 1903 if (rv != BFCMAP_E_NONE) { 1904 LOG_ERROR(BSL_LS_SOC_PHY, 1905 (BSL_META_U(unit, 1906 "Failed u=%d p=%d enable=%d rv=%d\n"), 1907 unit, port, enable, rv)); 1908 return SOC_E_FAIL; 1909 } 1910 LOG_INFO(BSL_LS_SOC_PHY, 1911 (BSL_META_U(unit, 1912 "Success u=%d p=%d enable=%d rv=%d\n"), 1913 unit, port, enable, rv)); 1914 1915 return SOC_E_NONE; 1916 } 1917 #endif 1918 1919 if ( FLAGS(pc) & PHY8806X_PM ) { 1920 return SOC_E_NONE; 1921 } 1922 1923 pmc = &pc->phymod_ctrl; 1924 pm_phy = &pmc->phy[0]->pm_phy; 1925 SOC_IF_ERROR_RETURN 1926 (phymod_port_enable_set(pm_phy, (uint32_t)enable)); 1927 1928 return (SOC_E_NONE); 1929 } 1930 1931 /* 1932 * Function: 1933 * phy_8806x_enable_get 1934 * Purpose: 1935 * Enable/Disable phy 1936 * Parameters: 1937 * unit - BCM unit number. 1938 * port - Port number. 1939 * enable - on/off state to set 1940 * Returns: 1941 * SOC_E_NONE 1942 */ 1943 STATIC int 1944 phy_8806x_enable_get(int unit, soc_port_t port, int *enable) 1945 { 1946 phy_ctrl_t *pc; 1947 soc_phymod_ctrl_t *pmc; 1948 phymod_phy_access_t *pm_phy; 1949 1950 /* locate phy control */ 1951 pc = EXT_PHY_SW_STATE(unit, port); 1952 if (pc == NULL) { 1953 return SOC_E_INTERNAL; 1954 } 1955 1956 #if defined(INCLUDE_FCMAP) 1957 /* Skip for FC */ 1958 if (pc->fcmap_enable) { 1959 *enable = 1; 1960 return SOC_E_NONE; 1961 } 1962 #endif 1963 1964 if ( FLAGS(pc) & PHY8806X_PM ) { 1965 return SOC_E_NONE; 1966 } 1967 1968 pmc = &pc->phymod_ctrl; 1969 pm_phy = &pmc->phy[0]->pm_phy; 1970 SOC_IF_ERROR_RETURN 1971 (phymod_port_enable_get(pm_phy, (uint32_t*)enable)); 1972 1973 *enable = 1; 1974 return (SOC_E_NONE); 1975 } 1976 1977 1978 /* 1979 * Function: 1980 * phy_8806x_duplex_get 1981 * Purpose: 1982 * Get PHY duplex mode 1983 * Parameters: 1984 * unit - BCM unit number. 1985 * port - Port number. 1986 * duplex - current duplex mode 1987 * Returns: 1988 * SOC_E_NONE 1989 */ 1990 STATIC int 1991 phy_8806x_duplex_get(int unit, soc_port_t port, int *duplex) 1992 { 1993 *duplex = TRUE; 1994 return SOC_E_NONE; 1995 } 1996 1997 /* 1998 * Function: 1999 * phy_8806x_speed_set 2000 * Purpose: 2001 * Set PHY speed 2002 * Parameters: 2003 * unit - BCM unit number. 2004 * port - Port number. 2005 * speed - link speed in Mbps 2006 * Returns: 2007 * SOC_E_NONE 2008 */ 2009 2010 STATIC int 2011 phy_8806x_speed_set(int unit, soc_port_t port, int speed) 2012 { 2013 phy_ctrl_t *pc; 2014 phy8806x_config_t *pCfg; 2015 soc_phymod_ctrl_t *pmc; 2016 soc_phymod_phy_t *phy; 2017 phymod_phy_inf_config_t interface_config; 2018 int rv = SOC_E_NONE; 2019 phy_ctrl_t *int_pc; 2020 phymod_ref_clk_t ref_clock; 2021 2022 /* locate phy control */ 2023 pc = EXT_PHY_SW_STATE(unit, port); 2024 if (pc == NULL) { 2025 return SOC_E_INTERNAL; 2026 } 2027 2028 if ((speed == 0) || ( FLAGS(pc) & PHY8806X_PM )) { 2029 return SOC_E_NONE; 2030 } 2031 2032 int_pc = INT_PHY_SW_STATE(unit, port); 2033 2034 if (NULL != int_pc) { 2035 rv = PHY_SPEED_SET(int_pc->pd, unit, port, speed); 2036 } 2037 2038 pmc = &pc->phymod_ctrl; 2039 pCfg = (phy8806x_config_t *) pc->driver_data; 2040 2041 phy = pmc->phy[0]; 2042 if (phy == NULL) { 2043 return SOC_E_INTERNAL; 2044 } 2045 2046 ref_clock = phymodRefClk156Mhz; 2047 SOC_IF_ERROR_RETURN 2048 (phymod_phy_interface_config_get(&phy->pm_phy, 2049 0, ref_clock, &interface_config)); 2050 interface_config.data_rate = speed; 2051 2052 /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */ 2053 SOC_IF_ERROR_RETURN 2054 (phymod_phy_interface_config_set(&phy->pm_phy, 2055 0 /* flags */, &interface_config)); 2056 2057 /* record success */ 2058 pCfg->speed_config.speed = speed; 2059 2060 pc->fiber.force_speed = speed;; 2061 return (rv); 2062 } 2063 2064 /* 2065 * Function: 2066 * phy_8806x_speed_get 2067 * Purpose: 2068 * Get PHY speed 2069 * Parameters: 2070 * unit - BCM unit number. 2071 * port - Port number. 2072 * speed - current link speed in Mbps 2073 * Returns: 2074 * SOC_E_NONE 2075 */ 2076 STATIC int 2077 phy_8806x_speed_get(int unit, soc_port_t port, int *speed) 2078 { 2079 phy_ctrl_t *pc; 2080 soc_phymod_ctrl_t *pmc; 2081 soc_phymod_phy_t *phy; 2082 phymod_phy_inf_config_t interface_config; 2083 int flag = 0; 2084 phymod_ref_clk_t ref_clock; 2085 int an = 0; 2086 int an_done = 0; 2087 phy_ctrl_t *int_pc = NULL; 2088 phy8806x_speed_config_t *speed_config; 2089 phy8806x_config_t *pCfg; 2090 2091 #if 0 2092 #if defined(INCLUDE_FCMAP) 2093 uint32_t xmodtxbuff[XMOD_BUFFER_MAX_LEN/4]; 2094 uint32_t xmodrxbuff[XMOD_BUFFER_MAX_LEN/4]; 2095 uint8_t *buftxptr, *bufrxptr; 2096 int xmodtxlen, xmodrxlen; 2097 uint32_t x_cmd, x_response, cmd; 2098 uint16_t fc_spd = 0; 2099 int rv; 2100 #endif 2101 #endif 2102 2103 /* locate phy control */ 2104 pc = EXT_PHY_SW_STATE(unit, port); 2105 if (pc == NULL) { 2106 return SOC_E_INTERNAL; 2107 } 2108 2109 2110 #if 0 2111 #if defined(INCLUDE_FCMAP) 2112 if (pc->fcmap_enable) { 2113 cmd = 0x4; 2114 x_cmd = HOST2LE32(cmd); 2115 2116 /* write args to xmod buffer */ 2117 buftxptr = (uint8_t *)xmodtxbuff; 2118 WRITE_XMOD_ARG_BUFF(buftxptr, &x_cmd, sizeof(x_cmd)); 2119 xmodtxlen = sizeof(x_cmd); 2120 xmodtxlen = GET_XMOD_BUF_WORD_LEN(xmodtxlen); 2121 2122 xmodrxlen = sizeof(x_response); 2123 xmodrxlen = GET_XMOD_BUF_WORD_LEN(xmodrxlen); 2124 2125 /* call xmod */ 2126 rv = phy_8806x_xmod_command(pc->unit, pc->port, XMOD_CMD_MODE_CORE(XMOD_DEV_DEBUG_CMD), xmodtxbuff, xmodtxlen, xmodrxbuff, xmodrxlen); 2127 2128 /* retrieve the argument from the xmod rx buffer */ 2129 bufrxptr = (uint8_t *)xmodrxbuff; 2130 READ_XMOD_ARG_BUFF(bufrxptr, &x_response, sizeof(x_response)); 2131 fc_spd = LE2HOST32(x_response); 2132 /* Set speed to 10G */ 2133 *speed = 10000 ; 2134 2135 return SOC_E_NONE; 2136 } 2137 #endif 2138 #endif 2139 2140 pCfg = (phy8806x_config_t *) pc->driver_data; 2141 speed_config = &(pCfg->speed_config); 2142 int_pc = INT_PHY_SW_STATE(unit, port); 2143 2144 if (speed_config->port_mode == ETH_REPEATER) { 2145 if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) { 2146 /* If forced repeater AN mode */ 2147 SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, speed)); 2148 return (SOC_E_NONE); 2149 } else if (speed_config->repeater_an_phase == 0) { 2150 *speed = 0; 2151 LED_SPEED(pc) = 0; 2152 return (SOC_E_NONE); 2153 } else if (speed_config->repeater_an_phase == 1) { 2154 pmc = &pc->phymod_ctrl; 2155 phy = pmc->phy[0]; 2156 ref_clock = phymodRefClk156Mhz; 2157 /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */ 2158 SOC_IF_ERROR_RETURN 2159 (phymod_phy_interface_config_get(&phy->pm_phy, 2160 flag, ref_clock, &interface_config)); 2161 *speed = interface_config.data_rate; 2162 LED_SPEED(pc) = *speed; 2163 return(SOC_E_NONE); 2164 } else if (speed_config->repeater_an_phase >= 1) { 2165 *speed = speed_config->repeater_an_resolved_speed; 2166 LED_SPEED(pc) = *speed; 2167 return(SOC_E_NONE); 2168 } 2169 } 2170 2171 SOC_IF_ERROR_RETURN 2172 (phy_8806x_an_get(unit, port, &an, &an_done)); 2173 2174 if ( an ) { 2175 if ( !an_done ) { 2176 #if 0 2177 LOG_CLI((BSL_META_U(unit, 2178 "phy_8806x_speed_get: AN not done, return \n"))); 2179 #endif 2180 *speed = 0; 2181 LED_SPEED(pc) = 0; 2182 return(SOC_E_NONE); 2183 } 2184 } 2185 2186 pmc = &pc->phymod_ctrl; 2187 2188 /* initialize the data structure */ 2189 interface_config.data_rate = 0; 2190 2191 /* now loop through all cores */ 2192 phy = pmc->phy[0]; 2193 if (phy == NULL) { 2194 return SOC_E_INTERNAL; 2195 } 2196 2197 pCfg = (phy8806x_config_t *) pc->driver_data; 2198 speed_config = &(pCfg->speed_config); 2199 2200 if (speed_config->port_mode == ETH_REPEATER) { 2201 int_pc = INT_PHY_SW_STATE(unit, port); 2202 SOC_IF_ERROR_RETURN(PHY_SPEED_GET(int_pc->pd, unit, port, speed)); 2203 } else { 2204 ref_clock = phymodRefClk156Mhz; 2205 /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */ 2206 SOC_IF_ERROR_RETURN 2207 (phymod_phy_interface_config_get(&phy->pm_phy, 2208 flag, ref_clock, &interface_config)); 2209 *speed = interface_config.data_rate; 2210 } 2211 LED_SPEED(pc) = *speed; 2212 return (SOC_E_NONE); 2213 } 2214 2215 #define AN_MAX_RETRY 10 2216 2217 /* 2218 * Function: 2219 * phy_8806x_an_set 2220 * Purpose: 2221 * Enable or disable auto-negotiation on the specified port. 2222 * Parameters: 2223 * unit - BCM unit number. 2224 * port - Port number. 2225 * an - Boolean, if true, auto-negotiation is enabled 2226 * (and/or restarted). If false, autonegotiation is disabled. 2227 * Returns: 2228 * SOC_E_XXX _soc_triumph_tx 2229 */ 2230 STATIC int 2231 phy_8806x_an_set(int unit, soc_port_t port, int enable) 2232 { 2233 phy_ctrl_t *pc; 2234 phy8806x_config_t *pCfg; 2235 soc_phymod_ctrl_t *pmc; 2236 soc_phymod_phy_t *phy; 2237 phymod_autoneg_control_t an; 2238 soc_info_t *si; 2239 phymod_phy_an_status_t an_status; 2240 phymod_an_try_enable_control_t an_ctrl; 2241 phy8806x_speed_config_t* speed_config; 2242 phy_ctrl_t *int_pc; 2243 uint32_t fec_val; 2244 2245 /* locate phy control */ 2246 pc = EXT_PHY_SW_STATE(unit, port); 2247 if (pc == NULL) { 2248 return SOC_E_INTERNAL; 2249 } 2250 2251 int_pc = INT_PHY_SW_STATE(unit, port); 2252 2253 #if defined(INCLUDE_FCMAP) 2254 /* Skip for FC */ 2255 if (pc->fcmap_enable) { 2256 return SOC_E_NONE; 2257 } 2258 #endif 2259 2260 phymod_autoneg_control_t_init(&an); 2261 pmc = &pc->phymod_ctrl; 2262 pCfg = (phy8806x_config_t *) pc->driver_data; 2263 speed_config = &(pCfg->speed_config); 2264 si = &SOC_INFO(unit); 2265 2266 /* only request autoneg on the first core */ 2267 phy = pmc->phy[0]; 2268 if (phy == NULL) { 2269 return SOC_E_INTERNAL; 2270 } 2271 an_ctrl.enable = enable; 2272 an_ctrl.num_lane_adv = si->port_num_lanes[port]; 2273 an_ctrl.an_mode = phymod_AN_MODE_NONE; 2274 if(pCfg->cl73an) { 2275 switch (pCfg->cl73an) { 2276 case PHY8806X_CL73_W_BAM: 2277 an_ctrl.an_mode = phymod_AN_MODE_CL73BAM; 2278 break ; 2279 case PHY8806X_CL73_WO_BAM: 2280 an_ctrl.an_mode = phymod_AN_MODE_CL73; 2281 break ; 2282 case PHY8806X_CL73_HPAM_VS_SW: 2283 an_ctrl.an_mode = phymod_AN_MODE_HPAM; 2284 break ; /* against TD+ */ 2285 case PHY8806X_CL73_HPAM: 2286 an_ctrl.an_mode = phymod_AN_MODE_HPAM; 2287 break ; /* against TR3 */ 2288 case PHY8806X_CL73_CL37: 2289 an_ctrl.an_mode = phymod_AN_MODE_CL73; 2290 break ; 2291 default: 2292 break; 2293 } 2294 } 2295 2296 pc->fiber.autoneg_enable = enable; 2297 2298 if (!enable) { 2299 an.enable = 0; /* Disable AN */ 2300 an.num_lane_adv = si->port_num_lanes[port]; 2301 an.an_mode = an_ctrl.an_mode; 2302 SOC_IF_ERROR_RETURN 2303 (phymod_phy_autoneg_set(&phy->pm_phy, &an)); 2304 if (speed_config->repeater_an_phase > REPEATER_AN_PHASE_NONE) { 2305 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION, 0); 2306 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, 0); 2307 } 2308 speed_config->repeater_an_phase = REPEATER_AN_PHASE_NONE; 2309 speed_config->repeater_an_resolved_speed = 0; 2310 speed_config->repeater_an_retry_phase0 = 0; 2311 2312 if ((speed_config->port_mode == ETH_REPEATER) && (speed_config->speed == 100000)) { 2313 fec_val = 0; 2314 PHY_CONTROL_SET(int_pc->pd, unit, port, SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91, fec_val); 2315 #ifdef PORTMOD_SUPPORT 2316 if (FLAGS(pc) & PHY8806X_PORTMOD) { 2317 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 2318 PHYMOD_FEC_CL91_SET(fec_val); 2319 portmod_port_fec_enable_set(unit, port, PORTMOD_INIT_F_INTERNAL_SERDES_ONLY, fec_val); 2320 } 2321 #endif 2322 } 2323 2324 } else { 2325 an_ctrl.speed = pc->speed_max; 2326 if (speed_config->port_mode == ETH_REPEATER) { 2327 if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) { 2328 speed_config->repeater_an_phase = REPEATER_AN_PHASE_0; 2329 /* Send SET_AN XMOD command to FW for enabling AutoNeg phase 0. */ 2330 SOC_IF_ERROR_RETURN 2331 (phymod_phy_autoneg_try_enable(&phy->pm_phy, &an_ctrl, &an_status)); 2332 return (SOC_E_NONE); 2333 } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_1) { 2334 an_ctrl.speed = speed_config->repeater_an_resolved_speed; 2335 SOC_IF_ERROR_RETURN 2336 (phymod_phy_autoneg_try_enable(&phy->pm_phy, &an_ctrl, &an_status)); 2337 return (SOC_E_NONE); 2338 } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_2) { 2339 return (SOC_E_NONE); 2340 } 2341 } 2342 2343 /* Send SET_AN XMOD command to FW for enabling AutoNeg. */ 2344 SOC_IF_ERROR_RETURN 2345 (phymod_phy_autoneg_try_enable(&phy->pm_phy, &an_ctrl, &an_status)); 2346 } 2347 2348 return (SOC_E_NONE); 2349 } 2350 2351 /* 2352 * Function: 2353 * phy_8806x_an_get 2354 * Purpose: 2355 * Get the current auto-negotiation status (enabled/busy) 2356 * Parameters: 2357 * unit - BCM unit number. 2358 * port - Port number. 2359 * an - (OUT) if true, auto-negotiation is enabled. 2360 * an_done - (OUT) if true, auto-negotiation is complete. This 2361 * value is undefined if an == false. 2362 * Returns: 2363 * SOC_E_XXX 2364 */ 2365 2366 STATIC int 2367 phy_8806x_an_get(int unit, soc_port_t port, int *an, int *an_done) 2368 { 2369 phy_ctrl_t* pc; 2370 soc_phymod_ctrl_t *pmc; 2371 phymod_phy_access_t *pm_phy; 2372 phymod_autoneg_control_t an_control; 2373 int idx, an_complete; 2374 phy8806x_config_t *pCfg; 2375 phy8806x_speed_config_t *speed_config; 2376 phy_ctrl_t *int_pc; 2377 int link; 2378 2379 pc = EXT_PHY_SW_STATE(unit, port); 2380 pmc = &pc->phymod_ctrl; 2381 2382 pCfg = (phy8806x_config_t *) pc->driver_data; 2383 speed_config = &(pCfg->speed_config); 2384 2385 #if defined(INCLUDE_FCMAP) 2386 /* Skip for FC */ 2387 if (pc->fcmap_enable) { 2388 return SOC_E_NONE; 2389 } 2390 #endif 2391 2392 int_pc = INT_PHY_SW_STATE(unit, port); 2393 2394 sal_memset(&an_control, 0x0, sizeof(an_control)); 2395 for (idx = 0; idx < pmc->num_phys; idx++) { 2396 pm_phy = &pmc->phy[idx]->pm_phy; 2397 SOC_IF_ERROR_RETURN 2398 (phymod_phy_autoneg_get(pm_phy, &an_control, (uint32_t *) &an_complete)); 2399 } 2400 2401 if (speed_config->port_mode != ETH_REPEATER) { 2402 if (an_control.enable) { 2403 *an = 1; 2404 *an_done = an_complete; 2405 } else { 2406 *an = 0; 2407 *an_done = 0; 2408 } 2409 } else if (speed_config->repeater_an_phase == REPEATER_AN_PHASE_NONE) { 2410 *an = 0; 2411 *an_done = 0; 2412 } else if (speed_config->repeater_an_phase >= REPEATER_AN_PHASE_0) { 2413 *an = 1; 2414 *an_done = 0; 2415 } else if (speed_config->repeater_an_phase >= REPEATER_AN_PHASE_1) { 2416 *an = 1; 2417 PHY_LINK_GET(int_pc->pd, unit, port, &link); 2418 if (link) 2419 *an_done = 1; 2420 } else if (speed_config->repeater_an_phase >= REPEATER_AN_PHASE_2) { 2421 *an = 1; 2422 *an_done = 1; 2423 } 2424 2425 return (SOC_E_NONE); 2426 } 2427 2428 /* 2429 * Function: 2430 * phy_8806x_ability_advert_set 2431 * Purpose: 2432 * Set the current advertisement for auto-negotiation. 2433 * Parameters: 2434 * unit - BCM unit number. 2435 * port - Port number. 2436 * ability - Port mode mask indicating supported options/speeds. 2437 * Returns: 2438 * SOC_E_XXX 2439 * Notes: 2440 * The advertisement is set only for the ACTIVE medium. 2441 * No synchronization performed at this level. 2442 */ 2443 2444 STATIC int 2445 phy_8806x_ability_advert_set(int unit, soc_port_t port, 2446 soc_port_ability_t *ability) 2447 { 2448 phy_ctrl_t *pc; 2449 phy8806x_config_t *pCfg; 2450 soc_phymod_ctrl_t *pmc; 2451 soc_phymod_phy_t *phy; 2452 int port_num_lanes; 2453 int line_interface; 2454 uint32_t an_tech_ability; 2455 uint32_t an_bam37_ability; 2456 uint32_t an_bam73_ability; 2457 _shr_port_mode_t speed_full_duplex; 2458 phymod_autoneg_ability_t phymod_autoneg_ability; 2459 phy8806x_speed_config_t* speed_config; 2460 2461 /* locate phy control */ 2462 pc = EXT_PHY_SW_STATE(unit, port); 2463 if (pc == NULL) { 2464 return SOC_E_INTERNAL; 2465 } 2466 2467 #if defined(INCLUDE_FCMAP) 2468 /* Skip for FC */ 2469 if (pc->fcmap_enable) { 2470 return SOC_E_NONE; 2471 } 2472 #endif 2473 2474 phymod_autoneg_ability_t_init(&phymod_autoneg_ability); 2475 2476 pmc = &pc->phymod_ctrl; 2477 pCfg = (phy8806x_config_t *) pc->driver_data; 2478 2479 /* only set abilities on the first core */ 2480 phy = pmc->phy[0]; 2481 if (phy == NULL) { 2482 return SOC_E_INTERNAL; 2483 } 2484 2485 pCfg = (phy8806x_config_t *) pc->driver_data; 2486 port_num_lanes = pCfg->speed_config.ln_lane_count; 2487 line_interface = pCfg->speed_config.line_interface; 2488 2489 an_tech_ability = 0; 2490 an_bam37_ability = 0; 2491 an_bam73_ability = 0; 2492 speed_full_duplex = ability->speed_full_duplex; 2493 2494 /* 2495 an_tech_ability 2496 */ 2497 if (port_num_lanes == 4) { 2498 if (ability->medium) { 2499 if (speed_full_duplex & SOC_PA_SPEED_100GB) { 2500 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) { 2501 PHYMOD_AN_CAP_100G_KR4_SET(an_tech_ability); 2502 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) { 2503 PHYMOD_AN_CAP_100G_CR4_SET(an_tech_ability); 2504 } else { 2505 PHYMOD_AN_CAP_100G_KR4_SET(an_tech_ability); 2506 } 2507 } 2508 if (speed_full_duplex & SOC_PA_SPEED_40GB) { 2509 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) { 2510 PHYMOD_AN_CAP_40G_KR4_SET(an_tech_ability); 2511 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) { 2512 PHYMOD_AN_CAP_40G_CR4_SET(an_tech_ability); 2513 } else { 2514 PHYMOD_AN_CAP_40G_KR4_SET(an_tech_ability); 2515 } 2516 } 2517 } else { 2518 if (speed_full_duplex & SOC_PA_SPEED_100GB) { 2519 if (line_interface & (1 << SOC_PORT_IF_CR4)) { 2520 PHYMOD_AN_CAP_100G_CR4_SET(an_tech_ability); 2521 } else { 2522 PHYMOD_AN_CAP_100G_KR4_SET(an_tech_ability); 2523 } 2524 } 2525 if (speed_full_duplex & SOC_PA_SPEED_40GB) { 2526 if (line_interface & (1 << SOC_PORT_IF_CR4)) { 2527 PHYMOD_AN_CAP_40G_CR4_SET(an_tech_ability); 2528 } else { 2529 PHYMOD_AN_CAP_40G_KR4_SET(an_tech_ability); 2530 } 2531 } 2532 } 2533 } else if (port_num_lanes == 2) { 2534 if (ability->medium) { 2535 if (speed_full_duplex & SOC_PA_SPEED_20GB) { 2536 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) { 2537 PHYMOD_BAM_CL73_CAP_20G_KR2_SET(an_bam73_ability); 2538 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) { 2539 PHYMOD_BAM_CL73_CAP_20G_CR2_SET(an_bam73_ability); 2540 } else { 2541 PHYMOD_BAM_CL73_CAP_20G_KR2_SET(an_bam73_ability); 2542 } 2543 } 2544 if (speed_full_duplex & SOC_PA_SPEED_40GB) { 2545 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) { 2546 PHYMOD_BAM_CL73_CAP_40G_KR2_SET(an_bam73_ability); 2547 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) { 2548 PHYMOD_BAM_CL73_CAP_40G_CR2_SET(an_bam73_ability); 2549 } else { 2550 PHYMOD_BAM_CL73_CAP_40G_KR2_SET(an_bam73_ability); 2551 } 2552 } 2553 if (speed_full_duplex & SOC_PA_SPEED_50GB) { 2554 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) { 2555 PHYMOD_BAM_CL73_CAP_50G_KR2_SET(an_bam73_ability); 2556 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) { 2557 PHYMOD_BAM_CL73_CAP_50G_CR2_SET(an_bam73_ability); 2558 } else { 2559 PHYMOD_BAM_CL73_CAP_50G_KR2_SET(an_bam73_ability); 2560 } 2561 } 2562 } else { 2563 if(speed_full_duplex & SOC_PA_SPEED_20GB) { 2564 /* need to fix CR2 bit shift issue */ 2565 if (line_interface & PHY8806X_IF_CR2) { 2566 PHYMOD_BAM_CL73_CAP_20G_CR2_SET(an_bam73_ability); 2567 } else { 2568 PHYMOD_BAM_CL73_CAP_20G_KR2_SET(an_bam73_ability); 2569 } 2570 } 2571 if(speed_full_duplex & SOC_PA_SPEED_40GB) { 2572 /* need to fix CR2 bit shift issue */ 2573 if (line_interface & PHY8806X_IF_CR2) { 2574 PHYMOD_BAM_CL73_CAP_40G_CR2_SET(an_bam73_ability); 2575 } else { 2576 PHYMOD_BAM_CL73_CAP_40G_KR2_SET(an_bam73_ability); 2577 } 2578 } 2579 if(speed_full_duplex & SOC_PA_SPEED_50GB) { 2580 /* need to fix CR2 bit shift issue */ 2581 if (line_interface & PHY8806X_IF_CR2) { 2582 PHYMOD_BAM_CL73_CAP_50G_CR2_SET(an_bam73_ability); 2583 } else { 2584 PHYMOD_BAM_CL73_CAP_50G_KR2_SET(an_bam73_ability); 2585 } 2586 } 2587 } 2588 } else { 2589 if ((ability->medium || ability->channel)) { 2590 if (speed_full_duplex & SOC_PA_SPEED_25GB) { 2591 if (ability->medium & SOC_PA_MEDIUM_BACKPLANE) { 2592 /* When in MSA AN mode : We do not want to populate the base page with IEEE mode. 2593 * If we do, then IEEE takes the higher priority. Hence we add the following exception 2594 * block for each 25G case below: if(pCfg->cl73an!=PHY8806X_MSA) */ 2595 if (pCfg->cl73an != PHY8806X_MSA) { 2596 if (ability->channel & SOC_PA_CHANNEL_SHORT) { 2597 PHYMOD_AN_CAP_25G_KRS1_SET(an_tech_ability); 2598 } else { 2599 PHYMOD_AN_CAP_25G_KR1_SET(an_tech_ability); 2600 } 2601 } 2602 PHYMOD_BAM_CL73_CAP_25G_KR1_SET(an_bam73_ability); 2603 } else if (ability->medium & SOC_PA_MEDIUM_COPPER) { 2604 if (pCfg->cl73an != PHY8806X_MSA) { 2605 if (ability->channel & SOC_PA_CHANNEL_SHORT) { 2606 PHYMOD_AN_CAP_25G_CRS1_SET(an_tech_ability); 2607 } else { 2608 PHYMOD_AN_CAP_25G_CR1_SET(an_tech_ability); 2609 } 2610 } 2611 PHYMOD_BAM_CL73_CAP_25G_CR1_SET(an_bam73_ability); 2612 } else { 2613 if (pCfg->cl73an != PHY8806X_MSA) { 2614 if (ability->channel & SOC_PA_CHANNEL_SHORT) { 2615 PHYMOD_AN_CAP_25G_KRS1_SET(an_tech_ability); 2616 } else { 2617 PHYMOD_AN_CAP_25G_KR1_SET(an_tech_ability); 2618 } 2619 } 2620 PHYMOD_BAM_CL73_CAP_25G_KR1_SET(an_bam73_ability); 2621 } 2622 } 2623 if (speed_full_duplex & SOC_PA_SPEED_10GB) { 2624 PHYMOD_AN_CAP_10G_KR_SET(an_tech_ability); 2625 } 2626 if (speed_full_duplex & SOC_PA_SPEED_1000MB) { 2627 PHYMOD_AN_CAP_1G_KX_SET(an_tech_ability); 2628 } 2629 } else { 2630 if(speed_full_duplex & SOC_PA_SPEED_25GB) { 2631 if (line_interface & (1 << SOC_PORT_IF_CR)) { 2632 /* next check if just CL73 or Cl73BAM */ 2633 PHYMOD_AN_CAP_25G_CR1_SET(an_tech_ability); 2634 PHYMOD_BAM_CL73_CAP_25G_CR1_SET(an_bam73_ability); 2635 } else { 2636 /* next check if just CL73 or Cl73BAM */ 2637 PHYMOD_AN_CAP_25G_KR1_SET(an_tech_ability); 2638 PHYMOD_BAM_CL73_CAP_25G_KR1_SET(an_bam73_ability); 2639 } 2640 } 2641 } 2642 } 2643 2644 if (port_num_lanes == 4) { /* 4 lanes */ 2645 if(speed_full_duplex & SOC_PA_SPEED_40GB) 2646 PHYMOD_BAM_CL37_CAP_40G_SET(an_bam37_ability); 2647 } else if (port_num_lanes == 2) { /* 2 lanes */ 2648 if(speed_full_duplex & SOC_PA_SPEED_20GB){ 2649 PHYMOD_BAM_CL37_CAP_20G_X2_SET(an_bam37_ability); 2650 PHYMOD_BAM_CL37_CAP_20G_X2_CX4_SET(an_bam37_ability); 2651 } 2652 } else { /* 1 lane */ 2653 if (speed_full_duplex & SOC_PA_SPEED_10GB) { 2654 PHYMOD_AN_CAP_10G_KR_SET(an_tech_ability); 2655 PHYMOD_AN_CAP_10G_KR_SET(an_tech_ability); 2656 } 2657 if (speed_full_duplex & SOC_PA_SPEED_1000MB) { 2658 PHYMOD_AN_CAP_1G_KX_SET(an_tech_ability); 2659 } 2660 } 2661 phymod_autoneg_ability.an_cap = an_tech_ability; 2662 phymod_autoneg_ability.cl73bam_cap = an_bam73_ability; 2663 phymod_autoneg_ability.cl37bam_cap = an_bam37_ability; 2664 2665 2666 PHYMOD_AN_CAP_SYMM_PAUSE_CLR(&phymod_autoneg_ability); 2667 PHYMOD_AN_CAP_ASYM_PAUSE_CLR(&phymod_autoneg_ability); 2668 2669 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 2670 case SOC_PA_PAUSE_TX: 2671 PHYMOD_AN_CAP_ASYM_PAUSE_SET(&phymod_autoneg_ability); 2672 break; 2673 case SOC_PA_PAUSE_RX: 2674 /* an_adv |= MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE; */ 2675 PHYMOD_AN_CAP_ASYM_PAUSE_SET(&phymod_autoneg_ability); 2676 PHYMOD_AN_CAP_SYMM_PAUSE_SET(&phymod_autoneg_ability); 2677 break; 2678 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 2679 PHYMOD_AN_CAP_SYMM_PAUSE_SET(&phymod_autoneg_ability); 2680 break; 2681 } 2682 2683 /* also set the sgmii speed */ 2684 phymod_autoneg_ability.sgmii_speed = phymod_CL37_SGMII_1000M; 2685 2686 /* next check if we need to set cl37 attribute */ 2687 if (pCfg->an_cl72) { 2688 phymod_autoneg_ability.an_cl72 = 1; 2689 } 2690 if (pCfg->hg_mode) { 2691 phymod_autoneg_ability.an_hg2 = 1; 2692 } 2693 2694 /*next need to check FEC ability */ 2695 if (ability->fec == SOC_PA_FEC_NONE) { 2696 PHYMOD_AN_FEC_OFF_SET(phymod_autoneg_ability.an_fec); 2697 } else { 2698 if (ability->fec & SOC_PA_FEC_CL74) 2699 PHYMOD_AN_FEC_CL74_SET(phymod_autoneg_ability.an_fec); 2700 if (ability->fec & SOC_PA_FEC_CL91) 2701 PHYMOD_AN_FEC_CL91_SET(phymod_autoneg_ability.an_fec); 2702 } 2703 2704 if (pCfg->an_fec == 1) 2705 PHYMOD_AN_FEC_CL74_SET(phymod_autoneg_ability.an_fec); 2706 else if (pCfg->an_fec == 2) 2707 PHYMOD_AN_FEC_CL91_SET(phymod_autoneg_ability.an_fec); 2708 2709 SOC_IF_ERROR_RETURN 2710 (phymod_phy_autoneg_ability_set(&phy->pm_phy, &phymod_autoneg_ability)); 2711 2712 pc->fiber.advert_ability = *ability; 2713 2714 speed_config = &(pCfg->speed_config); 2715 if (speed_config->an_fec) 2716 pc->fiber.advert_ability.fec = 1; 2717 else 2718 pc->fiber.advert_ability.fec = 0; 2719 2720 return SOC_E_NONE; 2721 } 2722 2723 /* 2724 * Function: 2725 * phy_8806x_ability_advert_get 2726 * Purpose: 2727 * Get the current advertisement for auto-negotiation. 2728 * Parameters: 2729 * unit - BCM unit number. 2730 * port - Port number. 2731 * ability - (OUT) Port mode mask indicating supported options/speeds. 2732 * Returns: 2733 * SOC_E_XXX 2734 * Notes: 2735 * The advertisement is retrieved for the ACTIVE medium. 2736 * No synchronization performed at this level. 2737 */ 2738 2739 STATIC int 2740 phy_8806x_ability_advert_get(int unit, soc_port_t port, 2741 soc_port_ability_t *ability) 2742 { 2743 phy_ctrl_t *pc; 2744 soc_phymod_ctrl_t *pmc; 2745 soc_phymod_phy_t *phy; 2746 int reg37_ability; 2747 int reg73_ability; 2748 int reg73bam_ability; 2749 int reg_ability; 2750 _shr_port_mode_t speed_full_duplex; 2751 phymod_autoneg_ability_t phymod_autoneg_ability; 2752 2753 /* locate phy control */ 2754 pc = EXT_PHY_SW_STATE(unit, port); 2755 if (pc == NULL) { 2756 return SOC_E_INTERNAL; 2757 } 2758 2759 #if defined(INCLUDE_FCMAP) 2760 if (pc->fcmap_enable) { 2761 ability->pause |= SOC_PA_PAUSE_TX; 2762 ability->pause |= SOC_PA_PAUSE_RX; 2763 return SOC_E_NONE; 2764 } 2765 #endif 2766 2767 pmc = &pc->phymod_ctrl; 2768 2769 /* only get abilities from the first core */ 2770 phy = pmc->phy[0]; 2771 if (phy == NULL) { 2772 return SOC_E_INTERNAL; 2773 } 2774 2775 phymod_autoneg_ability_t_init(&phymod_autoneg_ability); 2776 SOC_IF_ERROR_RETURN 2777 (phymod_phy_autoneg_ability_get(&phy->pm_phy, &phymod_autoneg_ability)); 2778 2779 2780 speed_full_duplex = 0; 2781 2782 /* retrieve CL73 abilities */ 2783 reg73_ability = phymod_autoneg_ability.an_cap; 2784 speed_full_duplex|= PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0; 2785 speed_full_duplex|= PHYMOD_AN_CAP_100G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0; 2786 speed_full_duplex|= PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0; 2787 speed_full_duplex|= PHYMOD_AN_CAP_40G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0; 2788 speed_full_duplex|= PHYMOD_AN_CAP_10G_KR_GET(reg73_ability) ?SOC_PA_SPEED_10GB:0; 2789 speed_full_duplex|= PHYMOD_AN_CAP_10G_KX4_GET(reg73_ability) ?SOC_PA_SPEED_10GB:0; 2790 speed_full_duplex|= PHYMOD_AN_CAP_1G_KX_GET(reg73_ability) ?SOC_PA_SPEED_1000MB:0; 2791 speed_full_duplex|= PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0; 2792 speed_full_duplex|= PHYMOD_AN_CAP_25G_KR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0; 2793 2794 /* retrieve CL73bam abilities */ 2795 reg73bam_ability = phymod_autoneg_ability.cl73bam_cap; 2796 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0; 2797 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0; 2798 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0; 2799 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0; 2800 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0; 2801 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0; 2802 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0; 2803 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_KR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0; 2804 2805 /* retrieve CL37 abilities */ 2806 reg37_ability = phymod_autoneg_ability.cl37bam_cap; 2807 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_40G_GET(reg37_ability) ? SOC_PA_SPEED_40GB:0; 2808 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_25P455G_GET(reg37_ability) ? SOC_PA_SPEED_25GB:0; 2809 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2810 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2811 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2812 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2813 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_10GB:0; 2814 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_DXGXS_GET(reg37_ability)? SOC_PA_SPEED_10GB:0; 2815 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_CX4_GET(reg37_ability)? SOC_PA_SPEED_10GB:0; 2816 2817 /* retrieve "pause" abilities */ 2818 reg_ability = phymod_autoneg_ability.capabilities; 2819 2820 ability->pause = 0; 2821 if (reg_ability == PHYMOD_AN_CAP_ASYM_PAUSE) { 2822 ability->pause = SOC_PA_PAUSE_TX; 2823 } else if (reg_ability == (PHYMOD_AN_CAP_SYMM_PAUSE|PHYMOD_AN_CAP_ASYM_PAUSE)) { 2824 ability->pause = SOC_PA_PAUSE_RX; 2825 } else if (reg_ability == PHYMOD_AN_CAP_SYMM_PAUSE) { 2826 ability->pause = (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX); 2827 } 2828 2829 ability->speed_full_duplex = speed_full_duplex; 2830 ability->encap = SOC_PA_ENCAP_IEEE | SOC_PA_ENCAP_HIGIG | SOC_PA_ENCAP_HIGIG2; 2831 if (PHYMOD_AN_CAP_25G_KRS1_GET(reg73_ability) || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability)) { 2832 ability->channel = SOC_PA_CHANNEL_SHORT; 2833 } else { 2834 ability->channel = SOC_PA_CHANNEL_LONG; 2835 } 2836 if (PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) || PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability) || 2837 PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability) || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability) || 2838 PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability) || PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) || 2839 PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability) || PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) || 2840 PHYMOD_BAM_CL73_CAP_50G_CR4_GET(reg73bam_ability)) { 2841 ability->medium = SOC_PA_MEDIUM_COPPER; 2842 } else { 2843 ability->medium = SOC_PA_MEDIUM_BACKPLANE; 2844 } 2845 2846 ability->fec = 0; 2847 if (PHYMOD_AN_FEC_OFF_GET(phymod_autoneg_ability.an_fec)) { 2848 ability->fec = SOC_PA_FEC_NONE; 2849 } else { 2850 if (PHYMOD_AN_FEC_CL74_GET(phymod_autoneg_ability.an_fec)) { 2851 ability->fec |= SOC_PA_FEC_CL74; 2852 } 2853 if (PHYMOD_AN_FEC_CL91_GET(phymod_autoneg_ability.an_fec)) { 2854 ability->fec |= SOC_PA_FEC_CL91; 2855 } 2856 } 2857 2858 return SOC_E_NONE; 2859 } 2860 2861 /* 2862 * Function: 2863 * phy_8806x_ability_remote_get 2864 * Purpose: 2865 * Get the current advertisement for auto-negotiation. 2866 * Parameters: 2867 * unit - BCM unit number. 2868 * port - Port number. 2869 * ability - (OUT) Port mode mask indicating supported options/speeds. 2870 * Returns: 2871 * SOC_E_XXX 2872 * Notes: 2873 * The advertisement is retrieved for the ACTIVE medium. 2874 * No synchronization performed at this level. 2875 */ 2876 2877 STATIC int 2878 phy_8806x_ability_remote_get(int unit, soc_port_t port, 2879 soc_port_ability_t *ability) 2880 { 2881 phy_ctrl_t *pc; 2882 soc_phymod_ctrl_t *pmc; 2883 soc_phymod_phy_t *phy; 2884 int reg73_ability; 2885 int reg73bam_ability; 2886 int reg37_ability; 2887 int reg_ability; 2888 _shr_port_mode_t speed_full_duplex; 2889 phymod_autoneg_ability_t phymod_autoneg_ability; 2890 2891 /* locate phy control */ 2892 pc = EXT_PHY_SW_STATE(unit, port); 2893 if (pc == NULL) { 2894 return SOC_E_INTERNAL; 2895 } 2896 2897 #if defined(INCLUDE_FCMAP) 2898 if (pc->fcmap_enable) { 2899 ability->pause |= SOC_PA_PAUSE_TX; 2900 ability->pause |= SOC_PA_PAUSE_RX; 2901 return SOC_E_NONE; 2902 } 2903 #endif 2904 2905 pmc = &pc->phymod_ctrl; 2906 2907 /* only get abilities from the first core */ 2908 phy = pmc->phy[0]; 2909 if (phy == NULL) { 2910 return SOC_E_INTERNAL; 2911 } 2912 2913 phymod_autoneg_ability_t_init(&phymod_autoneg_ability); 2914 SOC_IF_ERROR_RETURN 2915 (phymod_phy_autoneg_remote_ability_get(&phy->pm_phy, &phymod_autoneg_ability)); 2916 2917 speed_full_duplex = 0; 2918 2919 /* retrieve CL73 abilities */ 2920 reg73_ability = phymod_autoneg_ability.an_cap; 2921 speed_full_duplex|= PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0; 2922 speed_full_duplex|= PHYMOD_AN_CAP_100G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_100GB:0; 2923 speed_full_duplex|= PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0; 2924 speed_full_duplex|= PHYMOD_AN_CAP_40G_KR4_GET(reg73_ability) ?SOC_PA_SPEED_40GB:0; 2925 speed_full_duplex|= PHYMOD_AN_CAP_10G_KR_GET(reg73_ability) ?SOC_PA_SPEED_10GB:0; 2926 speed_full_duplex|= PHYMOD_AN_CAP_10G_KX4_GET(reg73_ability) ?SOC_PA_SPEED_10GB:0; 2927 speed_full_duplex|= PHYMOD_AN_CAP_1G_KX_GET(reg73_ability) ?SOC_PA_SPEED_1000MB:0; 2928 speed_full_duplex|= PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0; 2929 speed_full_duplex|= PHYMOD_AN_CAP_25G_KR1_GET(reg73_ability) ?SOC_PA_SPEED_25GB:0; 2930 2931 /* retrieve CL73bam abilities */ 2932 reg73bam_ability = phymod_autoneg_ability.cl73bam_cap; 2933 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0; 2934 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0; 2935 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0; 2936 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_40G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_40GB:0; 2937 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0; 2938 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_50G_KR2_GET(reg73bam_ability) ?SOC_PA_SPEED_50GB:0; 2939 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0; 2940 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_25G_KR1_GET(reg73bam_ability) ?SOC_PA_SPEED_25GB:0; 2941 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_CR1_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0; 2942 speed_full_duplex|= PHYMOD_BAM_CL73_CAP_20G_KR1_GET(reg73bam_ability) ?SOC_PA_SPEED_20GB:0; 2943 2944 /* retrieve CL37 abilities */ 2945 reg37_ability = phymod_autoneg_ability.cl37bam_cap; 2946 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_40G_GET(reg37_ability) ? SOC_PA_SPEED_40GB:0; 2947 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_25P455G_GET(reg37_ability) ? SOC_PA_SPEED_25GB:0; 2948 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2949 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X2_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2950 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2951 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_20G_X4_CX4_GET(reg37_ability)? SOC_PA_SPEED_20GB:0; 2952 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_X2_CX4_GET(reg37_ability)? SOC_PA_SPEED_10GB:0; 2953 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_DXGXS_GET(reg37_ability)? SOC_PA_SPEED_10GB:0; 2954 speed_full_duplex|= PHYMOD_BAM_CL37_CAP_10G_CX4_GET(reg37_ability)? SOC_PA_SPEED_10GB:0; 2955 2956 if (PHYMOD_AN_CAP_25G_KRS1_GET(reg73_ability) || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability)) { 2957 ability->channel |= SOC_PA_CHANNEL_SHORT; 2958 } else { 2959 ability->channel |= SOC_PA_CHANNEL_LONG; 2960 } 2961 if (PHYMOD_AN_CAP_100G_CR4_GET(reg73_ability) || PHYMOD_AN_CAP_40G_CR4_GET(reg73_ability) || 2962 PHYMOD_AN_CAP_25G_CR1_GET(reg73_ability) || PHYMOD_AN_CAP_25G_CRS1_GET(reg73_ability) || 2963 PHYMOD_BAM_CL73_CAP_20G_CR2_GET(reg73bam_ability) || PHYMOD_BAM_CL73_CAP_40G_CR2_GET(reg73bam_ability) || 2964 PHYMOD_BAM_CL73_CAP_50G_CR2_GET(reg73bam_ability) || PHYMOD_BAM_CL73_CAP_25G_CR1_GET(reg73bam_ability) || 2965 PHYMOD_BAM_CL73_CAP_50G_CR4_GET(reg73bam_ability)) { 2966 ability->medium = SOC_PA_MEDIUM_COPPER; 2967 } else { 2968 ability->medium = SOC_PA_MEDIUM_BACKPLANE; 2969 } 2970 2971 /* retrieve "pause" abilities */ 2972 reg_ability = phymod_autoneg_ability.capabilities; 2973 2974 ability->pause = 0; 2975 if (reg_ability == PHYMOD_AN_CAP_ASYM_PAUSE) { 2976 ability->pause = SOC_PA_PAUSE_TX; 2977 } else if (reg_ability == (PHYMOD_AN_CAP_SYMM_PAUSE|PHYMOD_AN_CAP_ASYM_PAUSE)) { 2978 ability->pause = SOC_PA_PAUSE_RX; 2979 } else if (reg_ability == PHYMOD_AN_CAP_SYMM_PAUSE) { 2980 ability->pause = (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX); 2981 } 2982 2983 ability->speed_full_duplex = speed_full_duplex; 2984 ability->encap = SOC_PA_ENCAP_IEEE | SOC_PA_ENCAP_HIGIG | SOC_PA_ENCAP_HIGIG2; 2985 2986 ability->fec = 0; 2987 if (PHYMOD_AN_FEC_OFF_GET(phymod_autoneg_ability.an_fec)) { 2988 ability->fec = SOC_PA_FEC_NONE; 2989 } else { 2990 if (PHYMOD_AN_FEC_CL74_GET(phymod_autoneg_ability.an_fec)) { 2991 ability->fec |= SOC_PA_FEC_CL74; 2992 } 2993 if (PHYMOD_AN_FEC_CL91_GET(phymod_autoneg_ability.an_fec)) { 2994 ability->fec |= SOC_PA_FEC_CL91; 2995 } 2996 } 2997 2998 return SOC_E_NONE; 2999 } 3000 3001 /* 3002 * Function: 3003 * phy_8806x_lb_set 3004 * Purpose: 3005 * Enable/disable PHY loopback mode 3006 * Parameters: 3007 * unit - BCM unit number. 3008 * port - Port number. 3009 * enable - binary value for on/off (1/0) 3010 * Returns: 3011 * SOC_E_NONE 3012 */ 3013 3014 STATIC int 3015 phy_8806x_lb_set(int unit, soc_port_t port, int enable) 3016 { 3017 phy_ctrl_t* pc; 3018 soc_phymod_ctrl_t *pmc; 3019 phymod_phy_access_t *pm_phy; 3020 int idx=0; 3021 phymod_loopback_mode_t lb_mode; 3022 3023 pc = EXT_PHY_SW_STATE(unit, port); 3024 3025 pmc = &pc->phymod_ctrl; 3026 3027 pm_phy = &pmc->phy[idx]->pm_phy; 3028 3029 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 3030 lb_mode = phymodLoopbackSysGlobal; 3031 SOC_IF_ERROR_RETURN 3032 (phymod_phy_loopback_set(pm_phy, lb_mode, enable)); 3033 } else { 3034 lb_mode = phymodLoopbackGlobal; 3035 #if defined(INCLUDE_FCMAP) 3036 if (pc->fcmap_enable) { 3037 lb_mode = phymodLoopbackGlobalPMD; 3038 } 3039 #endif 3040 SOC_IF_ERROR_RETURN 3041 (phymod_phy_loopback_set(pm_phy, lb_mode, enable)); 3042 } 3043 3044 return (SOC_E_NONE); 3045 } 3046 3047 /* 3048 * Function: 3049 * phy_8806x_lb_get 3050 * Purpose: 3051 * Get current PHY loopback mode 3052 * Parameters: 3053 * unit - BCM unit number. 3054 * port - Port number. 3055 * enable - address of location to store binary value for on/off (1/0) 3056 * Returns: 3057 * SOC_E_NONE 3058 */ 3059 STATIC int 3060 phy_8806x_lb_get(int unit, soc_port_t port, int *enable) 3061 { 3062 phy_ctrl_t* pc; 3063 soc_phymod_ctrl_t *pmc; 3064 phymod_phy_access_t *pm_phy; 3065 uint32 lb_enable = 0; 3066 int idx=0; 3067 3068 pc = EXT_PHY_SW_STATE(unit, port); 3069 #if defined(INCLUDE_FCMAP) 3070 /* Skip for FC */ 3071 if (pc->fcmap_enable) { 3072 return SOC_E_NONE; 3073 } 3074 #endif 3075 3076 pmc = &pc->phymod_ctrl; 3077 3078 *enable = 0; 3079 3080 pm_phy = &pmc->phy[idx]->pm_phy; 3081 3082 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 3083 SOC_IF_ERROR_RETURN 3084 (phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobal, &lb_enable)); 3085 } else { 3086 SOC_IF_ERROR_RETURN 3087 (phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobal, &lb_enable)); 3088 } 3089 3090 if (lb_enable) { 3091 *enable = 1; 3092 } 3093 3094 return (SOC_E_NONE); 3095 } 3096 3097 /* 3098 * Function: 3099 * phy_8806x_ability_local_get 3100 * Purpose: 3101 * xx 3102 * Parameters: 3103 * unit - BCM unit number. 3104 * port - Port number. 3105 * ability - xx 3106 * Returns: 3107 * SOC_E_NONE 3108 */ 3109 STATIC int 3110 phy_8806x_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 3111 { 3112 phy_ctrl_t *pc; 3113 /* phy8806x_config_t *pCfg; */ 3114 3115 pc = EXT_PHY_SW_STATE(unit, port); 3116 /* pCfg = (phy8806x_config_t *) pc->driver_data; */ 3117 3118 if (NULL == ability) { 3119 return SOC_E_PARAM; 3120 } 3121 3122 sal_memset(ability, 0, sizeof(*ability)); 3123 3124 ability->loopback = SOC_PA_LB_PHY; 3125 ability->medium = SOC_PA_MEDIUM_FIBER | SOC_PA_MEDIUM_COPPER | SOC_PA_MEDIUM_BACKPLANE; 3126 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 3127 ability->fec = SOC_PA_FEC_NONE |SOC_PA_FEC_CL74 | SOC_PA_FEC_CL91; 3128 ability->flags = SOC_PA_AUTONEG; 3129 3130 if (IND_LANE_MODE(pc)) { 3131 ability->speed_full_duplex = SOC_PA_SPEED_1000MB; 3132 switch(pc->speed_max) { /* must include all the supported speedss */ 3133 case 50000: 3134 ability->speed_full_duplex |= SOC_PA_SPEED_50GB; 3135 /* fall through */ 3136 case 40000: 3137 ability->speed_full_duplex |= SOC_PA_SPEED_40GB; 3138 /* fall through */ 3139 case 25000: 3140 ability->speed_full_duplex |= SOC_PA_SPEED_25GB; 3141 /* fall through */ 3142 case 20000: 3143 ability->speed_full_duplex |= SOC_PA_SPEED_20GB; 3144 /* fall through */ 3145 case 10000: 3146 ability->speed_full_duplex |= SOC_PA_SPEED_10GB; 3147 /* fall through */ 3148 default: 3149 break; 3150 } 3151 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 3152 ability->interface = SOC_PA_INTF_GMII | SOC_PA_INTF_SGMII; 3153 } else { 3154 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 3155 ability->speed_full_duplex = SOC_PA_SPEED_1000MB; 3156 switch(pc->speed_max) { 3157 case 106000: 3158 ability->speed_full_duplex |= SOC_PA_SPEED_106GB; 3159 /* Fall through */ 3160 case 100000: 3161 ability->speed_full_duplex |= SOC_PA_SPEED_100GB; 3162 /* Fall through */ 3163 case 40000: 3164 ability->speed_full_duplex |= SOC_PA_SPEED_40GB; 3165 /* Fall through */ 3166 default: 3167 ability->speed_full_duplex |= SOC_PA_SPEED_10GB; 3168 break; 3169 } 3170 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 3171 ability->interface = SOC_PA_INTF_XGMII; 3172 ability->loopback = SOC_PA_LB_PHY; 3173 ability->flags = SOC_PA_AUTONEG; 3174 } 3175 3176 return (SOC_E_NONE); 3177 } 3178 3179 /* 3180 * Function: 3181 * phy_8806x_firmware_set 3182 * Purpose: 3183 * xx 3184 * Parameters: 3185 * unit - BCM unit number. 3186 * port - Port number. 3187 3188 * Returns: 3189 * SOC_E_NONE 3190 */ 3191 3192 3193 STATIC int 3194 phy_8806x_firmware_set(int unit, int port, int offset, uint8 *data,int len) 3195 { 3196 phy_ctrl_t *pc; 3197 int dividend, divisor, rv = SOC_E_FAIL; 3198 uint32 temp32; 3199 uint16 temp16; 3200 uint16 status_l = 0, status_s = 0; 3201 3202 pc = EXT_PHY_SW_STATE(unit, port); 3203 3204 if (data) { 3205 return SOC_E_FAIL; 3206 } 3207 3208 switch (offset) { 3209 case PHYCTRL_UCODE_BCST_SETUP: 3210 /* Turn on broadcast mode */ 3211 3212 if ( FLAGS(pc) & PHY8806X_BMP0 ) { 3213 /* a.) bring all mHosts out of reset */ 3214 SOC_IF_ERROR_RETURN 3215 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3216 3217 temp32 &= ~0x40000015; 3218 /* temp32 |= (0xf << 6); */ /* RTS0 */ 3219 temp32 |= ((0xf << 6) | (0xff << 14)); /* RTS0 + SRAM0 */ 3220 3221 SOC_IF_ERROR_RETURN 3222 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3223 3224 /* temp32 &= ~(0xf << 6); */ 3225 temp32 &= ~((0xf << 6) | (0xff << 14)); 3226 3227 temp32 |= 0x40000015; 3228 SOC_IF_ERROR_RETURN 3229 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3230 /* b.) make sure that PLLs are locked */ 3231 3232 3233 3234 /* c.) place all mHosts in reset */ 3235 SOC_IF_ERROR_RETURN 3236 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3237 temp32 |= (0xf << 6); 3238 SOC_IF_ERROR_RETURN 3239 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3240 3241 /* d.) e.) combined together */ 3242 SOC_IF_ERROR_RETURN 3243 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32)); 3244 temp32 &= ~0xff; 3245 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 3246 temp32 |= (0x3 << ((pc->phy_id & 0x3) << 1)); 3247 } 3248 SOC_IF_ERROR_RETURN 3249 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32)); 3250 3251 /* f.) bring all mHosts out of reset */ 3252 SOC_IF_ERROR_RETURN 3253 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3254 temp32 &= ~(0xf << 6); 3255 SOC_IF_ERROR_RETURN 3256 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3257 3258 3259 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 3260 /* g.) */ 3261 SOC_IF_ERROR_RETURN 3262 (MODIFY_PHY8806X_AXI_CONTROL_F0_REG(unit, pc, (1U << 9), (1U << 9))); 3263 3264 SOC_IF_ERROR_RETURN 3265 (WRITE_PHY8806X_AXI_ADDR_UPPER_F0_REG(unit, pc, 0x0026 + (pc->phy_id & 0x3) * 0x10)); 3266 SOC_IF_ERROR_RETURN 3267 (WRITE_PHY8806X_AXI_ADDR_LOWER_F0_REG(unit, pc, 0x0000)); 3268 } 3269 3270 #if defined(INCLUDE_FCMAP) 3271 /* SDK-85976 : SW WAR for MONTREAL2-859 , only for A0*/ 3272 if (pc->fcmap_enable){ 3273 if (PHY_IS_BCM8806X_A0(pc)) { 3274 SOC_IF_ERROR_RETURN 3275 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0)); 3276 } 3277 } else { 3278 SOC_IF_ERROR_RETURN 3279 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf)); 3280 } 3281 if (pc->fcmap_enable) { 3282 SOC_IF_ERROR_RETURN 3283 (READ_TOP_SOFT_RESET_REG_2(unit, pc, &temp32)); 3284 temp32 |= 0x115; 3285 SOC_IF_ERROR_RETURN 3286 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, temp32)); 3287 } else { 3288 SOC_IF_ERROR_RETURN 3289 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100)); 3290 } 3291 #else 3292 SOC_IF_ERROR_RETURN 3293 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf)); 3294 SOC_IF_ERROR_RETURN 3295 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100)); 3296 #endif 3297 3298 SOC_IF_ERROR_RETURN 3299 (_pmd_enable(unit, pc, 0)); /* line */ 3300 SOC_IF_ERROR_RETURN 3301 (_pmd_enable(unit, pc, 1)); /* system */ 3302 3303 } else if ( FLAGS(pc) & PHY8806X_BMP1 ) { 3304 /* a.) bring all mHosts out of reset */ 3305 SOC_IF_ERROR_RETURN 3306 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3307 3308 temp32 &= ~0x8000002A; 3309 /* temp32 |= (0xf << 10); */ /* RTS1 */ 3310 temp32 |= ((0xf << 10) | (0xff << 22)); /* RTS1 + SRAM1 */ 3311 3312 SOC_IF_ERROR_RETURN 3313 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3314 3315 /* temp32 &= ~(0xf << 10); */ 3316 temp32 &= ~((0xf << 10) | (0xff << 22)); 3317 temp32 |= 0x8000002A; 3318 3319 SOC_IF_ERROR_RETURN 3320 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3321 /* b.) make sure that PLLs are locked */ 3322 3323 3324 3325 /* c.) place all mHosts in reset */ 3326 SOC_IF_ERROR_RETURN 3327 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3328 temp32 |= (0xf << 10); 3329 SOC_IF_ERROR_RETURN 3330 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3331 3332 /* d.) e.) combined together */ 3333 SOC_IF_ERROR_RETURN 3334 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32)); 3335 temp32 &= ~0xff00; 3336 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 3337 temp32 |= (0x3 << (((pc->phy_id & 0x3) << 1) + 8)); 3338 } 3339 SOC_IF_ERROR_RETURN 3340 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32)); 3341 3342 /* f.) bring all mHosts out of reset */ 3343 SOC_IF_ERROR_RETURN 3344 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3345 temp32 &= ~(0xf << 10); 3346 SOC_IF_ERROR_RETURN 3347 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3348 3349 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 3350 /* g.) */ 3351 SOC_IF_ERROR_RETURN 3352 (MODIFY_PHY8806X_AXI_CONTROL_F1_REG(unit, pc, (1U << 9), (1U << 9))); 3353 3354 SOC_IF_ERROR_RETURN 3355 (WRITE_PHY8806X_AXI_ADDR_UPPER_F1_REG(unit, pc, 0x0026 + (pc->phy_id & 0x3) * 0x10)); 3356 SOC_IF_ERROR_RETURN 3357 (WRITE_PHY8806X_AXI_ADDR_LOWER_F1_REG(unit, pc, 0x0000)); 3358 } 3359 #if defined(INCLUDE_FCMAP) 3360 /* SDK-85976 : SW WAR for MONTREAL2-859 , only for A0*/ 3361 if (pc->fcmap_enable){ 3362 if (PHY_IS_BCM8806X_A0(pc)) { 3363 SOC_IF_ERROR_RETURN 3364 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0)); 3365 } 3366 } else { 3367 SOC_IF_ERROR_RETURN 3368 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf)); 3369 } 3370 if (pc->fcmap_enable) { 3371 SOC_IF_ERROR_RETURN 3372 (READ_TOP_SOFT_RESET_REG_2(unit, pc, &temp32)); 3373 temp32 |= 0x115; 3374 SOC_IF_ERROR_RETURN 3375 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, temp32)); 3376 } else { 3377 SOC_IF_ERROR_RETURN 3378 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100)); 3379 } 3380 #else 3381 SOC_IF_ERROR_RETURN 3382 (WRITE_LINE_FCPORT_EXT_TX_DISABLE_CTRL(unit, pc, 0xf)); 3383 SOC_IF_ERROR_RETURN 3384 (WRITE_TOP_SOFT_RESET_REG_2(unit, pc, 0x100)); 3385 #endif 3386 3387 SOC_IF_ERROR_RETURN 3388 (_pmd_enable(unit, pc, 0)); /* line */ 3389 SOC_IF_ERROR_RETURN 3390 (_pmd_enable(unit, pc, 1)); /* system */ 3391 3392 } 3393 break; 3394 3395 case PHYCTRL_UCODE_BCST_uC_SETUP: 3396 break; 3397 case PHYCTRL_UCODE_BCST_ENABLE: 3398 if ( FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART) ) { 3399 break; 3400 } 3401 /* h.) */ 3402 if ( FLAGS(pc) & PHY8806X_FWDLM ) { 3403 SOC_IF_ERROR_RETURN 3404 (MODIFY_PHY8806X_MISC_CONTROL_REG(unit, pc, 0, (1U << 14))); 3405 } 3406 3407 if ( FLAGS(pc) & PHY8806X_CHM) { 3408 SOC_IF_ERROR_RETURN 3409 (MODIFY_PHY8806X_MISC_CONTROL_REG(unit, pc, (1U << 15), (1U << 15))); 3410 if ( FLAGS(pc) & PHY8806X_AC ) { 3411 if (DL_DIVIDEND(pc) && DL_DIVISOR(pc)) { 3412 rv = soc_cmic_rate_param_get(unit, ÷nd, &divisor); 3413 if (SOC_SUCCESS(rv)) { 3414 rv = soc_cmic_rate_param_set(unit, DL_DIVIDEND(pc), DL_DIVISOR(pc)); 3415 } 3416 } 3417 SOC_IF_ERROR_RETURN 3418 (_phy_8806x_write_to_arm(unit, pc, 0, FIRMWARE(pc), FIRMWARE_LEN(pc))); 3419 if (SOC_SUCCESS(rv)) { 3420 /* rv contains the return value of previous soc_cmic_rate_param_set() */ 3421 SOC_IF_ERROR_RETURN 3422 (soc_cmic_rate_param_set(unit, dividend, divisor)); 3423 } 3424 } 3425 } 3426 3427 break; 3428 3429 case PHYCTRL_UCODE_BCST_LOAD: 3430 if ( FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART) ) { 3431 break; 3432 } 3433 if (DL_DIVIDEND(pc) && DL_DIVISOR(pc)) { 3434 rv = soc_cmic_rate_param_get(unit, ÷nd, &divisor); 3435 if (SOC_SUCCESS(rv)) { 3436 rv = soc_cmic_rate_param_set(unit, DL_DIVIDEND(pc), DL_DIVISOR(pc)); 3437 } 3438 } 3439 3440 if ( FLAGS(pc) & PHY8806X_FWDLM ) { 3441 SOC_IF_ERROR_RETURN 3442 (_phy_8806x_write_to_arm(unit, pc, 0, FIRMWARE(pc), FIRMWARE_LEN(pc))); 3443 } 3444 if (SOC_SUCCESS(rv)) { 3445 /* rv contains the return value of previous soc_cmic_rate_param_set() */ 3446 SOC_IF_ERROR_RETURN 3447 (soc_cmic_rate_param_set(unit, dividend, divisor)); 3448 } 3449 if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) { 3450 soc_timeout_init(&TO(pc), 35000000, 0); 3451 } 3452 break; 3453 3454 case PHYCTRL_UCODE_BCST_END: 3455 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 3456 /* Turn off broadcast mode by reading the following reg. */ 3457 if ( FLAGS(pc) & PHY8806X_CHM ) { 3458 SOC_IF_ERROR_RETURN 3459 (READ_PHY8806X_MISC_CONTROL_REG(unit, pc, &temp16)); 3460 } 3461 3462 if ( FLAGS(pc) & PHY8806X_FWDLM ) { 3463 SOC_IF_ERROR_RETURN 3464 (MODIFY_PHY8806X_MISC_CONTROL_REG(unit, pc, (1U << 14), (1U << 14))); 3465 } 3466 } 3467 3468 if ( FLAGS(pc) & (PHY8806X_BMP0 | PHY8806X_BMP1) ) { 3469 SOC_IF_ERROR_RETURN 3470 (_pmd_disable(unit, pc, 0)); /* line */ 3471 SOC_IF_ERROR_RETURN 3472 (_pmd_disable(unit, pc, 1)); /* system */ 3473 3474 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 3475 temp16 = 0; 3476 do { 3477 rv = READ_PHY8806X_FW_TO_SW_MESSAGE_REG(unit, pc, &temp16); 3478 if (temp16 | SOC_FAILURE(rv)) { 3479 break; 3480 } 3481 } while (!soc_timeout_check(&TO(pc))); 3482 3483 LOG_CLI((BSL_META_U(unit, 3484 "PHY8806X_FW_TO_SW_MESSAGE_REG S : u=%d p=%d status=%04x" 3485 " !.\n"), unit, pc->port, temp16)); 3486 if ((temp16 & 0x5000) != 0x5000) { 3487 LOG_CLI((BSL_META_U(unit, 3488 "PHY8806X_FW_TO_SW_MESSAGE_REG failed: u=%d p=%d status=%04x" 3489 " !.\n"), unit, pc->port, temp16)); 3490 /* return SOC_E_FAIL; */ 3491 } 3492 } 3493 3494 temp32 = HOST2LE32(TOP_DEV_REV_ID(pc)); 3495 3496 /* Place the value in SRAM */ 3497 SOC_IF_ERROR_RETURN 3498 (_phy_8806x_axi_write(unit, pc, 0x00100000 + 0x100 - 0x4, &temp32, 1)); 3499 3500 /* Start PMDs */ 3501 SOC_IF_ERROR_RETURN 3502 (_pmd_start(unit, pc, 0)); /* line */ 3503 SOC_IF_ERROR_RETURN 3504 (_pmd_start(unit, pc, 1)); /* system */ 3505 3506 /* Read the stored length and the CRC from SRAM */ 3507 _phy_8806x_axi_read(unit, pc, 0x00100000, &temp32, 1); 3508 PMD_SIZE(pc) = LE2HOST32(temp32); 3509 _phy_8806x_axi_read(unit, pc, 0x00100004, &temp32, 1); 3510 PMD_CRC(pc) = LE2HOST32(temp32); 3511 3512 soc_timeout_init(&TO(pc), 5000000, 0); /* 5s timer */ 3513 3514 do { 3515 3516 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03d, &status_l); 3517 if (SOC_FAILURE(rv)) { 3518 break; 3519 } 3520 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03d, &status_s); 3521 if (SOC_FAILURE(rv)) { 3522 break; 3523 } 3524 if ((status_l== 0x80) && (status_s == 0x80)) { 3525 break; 3526 } 3527 } while (!soc_timeout_check(&TO(pc))); 3528 3529 if ( status_l != 0x80 ) { 3530 LOG_CLI((BSL_META_U(unit, 3531 "PHY8806X PMD (line) firmware not running: u=%d p=%d status=%04x" 3532 " !.\n"), unit, pc->port, status_l)); 3533 } else { 3534 /* Issue command to compute CRC */ 3535 _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03e, PMD_SIZE(pc), 0); 3536 _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 1, 1, 0, 0xd03d, 0x14, 0); 3537 } 3538 3539 if ( status_s != 0x80 ) { 3540 LOG_CLI((BSL_META_U(unit, 3541 "PHY8806X PMD (sys) firmware not running: u=%d p=%d status=%04x" 3542 " !.\n"), unit, pc->port, status_s)); 3543 } else { 3544 /* Issue command to compute CRC */ 3545 _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03e, PMD_SIZE(pc), 0); 3546 _tsc_reg_write(unit, pc, 0, (pc->phy_id & 0x7) + 9, 1, 0, 0xd03d, 0x14, 0); 3547 } 3548 3549 } 3550 3551 soc_timeout_init(&TO(pc), 5000000, 0); /* 5s timer */ 3552 3553 if ( FLAGS(pc) & PHY8806X_BMP0 ) { 3554 /* c.) place all mHosts in reset */ 3555 SOC_IF_ERROR_RETURN 3556 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3557 temp32 |= (0xf << 6); 3558 SOC_IF_ERROR_RETURN 3559 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3560 3561 /* d.) e.) combined together */ 3562 SOC_IF_ERROR_RETURN 3563 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32)); 3564 temp32 &= ~0xff; 3565 if (!( FLAGS(pc) & PHY8806X_PM )) { 3566 temp32 |= (0x2 << ((pc->phy_id & 0x3) << 1)); 3567 } 3568 SOC_IF_ERROR_RETURN 3569 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32)); 3570 3571 /* f.) Release all mHosts from reset, Only BMP will run. Others halted. 3572 In PM all will be halted. */ 3573 SOC_IF_ERROR_RETURN 3574 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3575 temp32 &= ~(0xf << 6); 3576 SOC_IF_ERROR_RETURN 3577 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3578 3579 } else if ( FLAGS(pc) & PHY8806X_BMP1 ) { 3580 /* c.) place all mHosts in reset */ 3581 SOC_IF_ERROR_RETURN 3582 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3583 temp32 |= (0xf << 10); 3584 SOC_IF_ERROR_RETURN 3585 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3586 3587 /* d.) e.) combined together */ 3588 SOC_IF_ERROR_RETURN 3589 (READ_TOP_RTS_MISC_CTRL_REG(unit, pc, &temp32)); 3590 temp32 &= ~0xff00; 3591 if (!( FLAGS(pc) & PHY8806X_PM )) { 3592 temp32 |= (0x2 << (((pc->phy_id & 0x3) << 1) + 8)); 3593 } 3594 SOC_IF_ERROR_RETURN 3595 (WRITE_TOP_RTS_MISC_CTRL_REG(unit, pc, temp32)); 3596 3597 /* f.) Release all mHosts from reset, Only BMP will run. Others halted. 3598 In PM all will be halted. */ 3599 SOC_IF_ERROR_RETURN 3600 (READ_TOP_SOFT_RESET_REG(unit, pc, &temp32)); 3601 temp32 &= ~(0xf << 10); 3602 SOC_IF_ERROR_RETURN 3603 (WRITE_TOP_SOFT_RESET_REG(unit, pc, temp32)); 3604 3605 } 3606 3607 break; 3608 3609 default: 3610 break; 3611 } 3612 3613 3614 3615 return SOC_E_NONE; 3616 } 3617 3618 STATIC int 3619 _phy_8806x_validate_interface_type(phy8806x_speed_config_t *speed_config, soc_port_if_t *pif) 3620 { 3621 int port_num_lanes; 3622 3623 port_num_lanes = speed_config->ln_lane_count; 3624 3625 switch (speed_config->speed) { 3626 case 1000: 3627 if (port_num_lanes == 1) { 3628 switch (*pif) { 3629 case SOC_PORT_IF_SGMII: 3630 case SOC_PORT_IF_GMII: 3631 break; 3632 default: 3633 *pif = SOC_PORT_IF_SGMII; 3634 } 3635 } else { 3636 return SOC_E_PARAM; 3637 } 3638 break; 3639 case 10000: 3640 case 25000: 3641 case 20000: 3642 if (port_num_lanes == 1) { 3643 switch (*pif) { 3644 case SOC_PORT_IF_CR: 3645 case SOC_PORT_IF_SR: 3646 case SOC_PORT_IF_KR: 3647 case SOC_PORT_IF_XFI: 3648 case SOC_PORT_IF_XAUI: 3649 break; 3650 case SOC_PORT_IF_LR: 3651 *pif = SOC_PORT_IF_SR; 3652 break; 3653 default: 3654 *pif = SOC_PORT_IF_CR; 3655 break; 3656 } 3657 } else if(port_num_lanes == 2) { 3658 switch (*pif) { 3659 case SOC_PORT_IF_CR2: 3660 case SOC_PORT_IF_SR2: 3661 case SOC_PORT_IF_KR2: 3662 break; 3663 case SOC_PORT_IF_LR2: 3664 *pif = SOC_PORT_IF_SR2; 3665 break; 3666 default: 3667 *pif = SOC_PORT_IF_CR2; 3668 break; 3669 } 3670 } else { 3671 return SOC_E_PARAM; 3672 } 3673 break ; 3674 case 40000: 3675 case 42000: 3676 case 50000: 3677 if (port_num_lanes == 2) { 3678 switch (*pif) { 3679 case SOC_PORT_IF_CR2: 3680 case SOC_PORT_IF_SR2: 3681 case SOC_PORT_IF_KR2: 3682 break; 3683 case SOC_PORT_IF_LR2: 3684 *pif = SOC_PORT_IF_SR2; 3685 break; 3686 default: 3687 *pif = SOC_PORT_IF_CR2; 3688 break; 3689 } 3690 } else if (port_num_lanes == 4) { 3691 switch (*pif) { 3692 case SOC_PORT_IF_CR4: 3693 case SOC_PORT_IF_SR4: 3694 case SOC_PORT_IF_KR4: 3695 case SOC_PORT_IF_XLAUI: 3696 break; 3697 case SOC_PORT_IF_LR4: 3698 *pif = SOC_PORT_IF_SR4; 3699 break; 3700 default: 3701 *pif = SOC_PORT_IF_CR4; 3702 break; 3703 } 3704 } else { 3705 return SOC_E_PARAM; 3706 } 3707 break; 3708 case 100000: 3709 case 106000: 3710 if (port_num_lanes == 4) { 3711 switch (*pif) { 3712 case SOC_PORT_IF_CR4: 3713 case SOC_PORT_IF_SR4: 3714 case SOC_PORT_IF_KR4: 3715 case SOC_PORT_IF_CAUI: 3716 break; 3717 case SOC_PORT_IF_LR4: 3718 *pif = SOC_PORT_IF_SR4; 3719 break; 3720 default: 3721 *pif = SOC_PORT_IF_CR4; 3722 break; 3723 } 3724 } else { 3725 return SOC_E_PARAM; 3726 } 3727 break; 3728 default: 3729 return SOC_E_PARAM; 3730 } 3731 3732 return 0; 3733 } 3734 3735 3736 STATIC int 3737 phy_8806x_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 3738 { 3739 phy_ctrl_t *pc; 3740 soc_phymod_ctrl_t *pmc; 3741 soc_phymod_phy_t *phy; 3742 phymod_phy_inf_config_t interface_config; 3743 int flag = 0; 3744 phymod_ref_clk_t ref_clock; 3745 phy8806x_speed_config_t *speed_config; 3746 phy8806x_config_t *pCfg; 3747 phymod_phy_access_t pm_phy_copy; 3748 3749 /* locate phy control */ 3750 pc = EXT_PHY_SW_STATE(unit, port); 3751 if (pc == NULL) { 3752 return SOC_E_INTERNAL; 3753 } 3754 3755 pmc = &pc->phymod_ctrl; 3756 3757 /* initialize the data structure */ 3758 sal_memset(&interface_config, 0x0, sizeof(phymod_phy_inf_config_t)); 3759 3760 /* now loop through all cores */ 3761 phy = pmc->phy[0]; 3762 if (phy == NULL) { 3763 return SOC_E_INTERNAL; 3764 } 3765 3766 ref_clock = phymodRefClk156Mhz; 3767 3768 sal_memcpy(&pm_phy_copy, &phy->pm_phy, sizeof(pm_phy_copy)); 3769 3770 pm_phy_copy.port_loc = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) \ 3771 ? phymodPortLocSys : ((pc->flags & PHYCTRL_LINE_SIDE_CTRL) \ 3772 ? phymodPortLocLine : phymodPortLocDC); 3773 3774 SOC_IF_ERROR_RETURN 3775 (phymod_phy_interface_config_get(&pm_phy_copy, 3776 flag, ref_clock, &interface_config)); 3777 3778 pCfg = (phy8806x_config_t *) pc->driver_data; 3779 speed_config = &(pCfg->speed_config); 3780 3781 if ((pif == SOC_PORT_IF_SFI) || 3782 (pif == SOC_PORT_IF_SR4) || 3783 (pif == SOC_PORT_IF_LR4) || 3784 (pif == SOC_PORT_IF_SR) || 3785 (pif == SOC_PORT_IF_SR2) || 3786 (pif == SOC_PORT_IF_LR) || 3787 (pif == SOC_PORT_IF_LR2) || 3788 (pif == SOC_PORT_IF_GMII)) { 3789 #if defined(INCLUDE_FCMAP) 3790 if (pc->fcmap_enable) 3791 pCfg->speed_config.fiber_pref_sys = 1; 3792 #endif 3793 pCfg->speed_config.fiber_pref = 1; 3794 } else { 3795 #if defined(INCLUDE_FCMAP) 3796 if (pc->fcmap_enable) 3797 pCfg->speed_config.fiber_pref_sys = 0; 3798 #endif 3799 pCfg->speed_config.fiber_pref = 0; 3800 } 3801 3802 SOC_IF_ERROR_RETURN(_phy_8806x_validate_interface_type(speed_config, &pif)); 3803 3804 /* coverity[mixed_enums]: ignore */ 3805 interface_config.interface_type = pif; 3806 3807 if (!interface_config.data_rate) 3808 interface_config.data_rate = pCfg->speed_config.speed; 3809 3810 /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */ 3811 SOC_IF_ERROR_RETURN 3812 (phymod_phy_interface_config_set(&pm_phy_copy, 3813 flag, &interface_config)); 3814 3815 return (SOC_E_NONE); 3816 } 3817 3818 STATIC int 3819 phy_8806x_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 3820 { 3821 phy_ctrl_t *pc; 3822 soc_phymod_ctrl_t *pmc; 3823 soc_phymod_phy_t *phy; 3824 phymod_phy_inf_config_t interface_config; 3825 int flag = 0; 3826 phymod_ref_clk_t ref_clock; 3827 phymod_phy_access_t pm_phy_copy; 3828 3829 /* locate phy control */ 3830 pc = EXT_PHY_SW_STATE(unit, port); 3831 if (pc == NULL) { 3832 return SOC_E_INTERNAL; 3833 } 3834 3835 pmc = &pc->phymod_ctrl; 3836 3837 /* initialize the data structure */ 3838 sal_memset(&interface_config, 0x0, sizeof(phymod_phy_inf_config_t)); 3839 3840 /* now loop through all cores */ 3841 phy = pmc->phy[0]; 3842 if (phy == NULL) { 3843 return SOC_E_INTERNAL; 3844 } 3845 3846 ref_clock = phymodRefClk156Mhz; 3847 3848 sal_memcpy(&pm_phy_copy, &phy->pm_phy, sizeof(pm_phy_copy)); 3849 3850 pm_phy_copy.port_loc = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) \ 3851 ? phymodPortLocSys : ((pc->flags & PHYCTRL_LINE_SIDE_CTRL) \ 3852 ? phymodPortLocLine : phymodPortLocDC); 3853 3854 /* note that the flags have an option to indicate whether it's ok to reprogram the PLL */ 3855 SOC_IF_ERROR_RETURN 3856 (phymod_phy_interface_config_get(&pm_phy_copy, 3857 flag, ref_clock, &interface_config)); 3858 3859 /* coverity[mixed_enums]: ignore */ 3860 *pif = interface_config.interface_type; 3861 3862 return (SOC_E_NONE); 3863 3864 } 3865 3866 3867 /* 3868 * Function: 3869 * phy8806x_uc_status_dump 3870 * Purpose: 3871 * display all the serdes related parameters 3872 * Parameters: 3873 * unit - BCM unit number. 3874 * port - Port number. 3875 3876 * Returns: 3877 * SOC_E_NONE 3878 */ 3879 STATIC int 3880 phy8806x_uc_status_dump(int unit, soc_port_t port, void *arg) 3881 { 3882 phy_ctrl_t* pc; 3883 soc_phymod_ctrl_t *pmc; 3884 phymod_phy_access_t *pm_phy; 3885 int idx; 3886 3887 /* locate phy control, phymod control, and the configuration data */ 3888 pc = EXT_PHY_SW_STATE(unit, port); 3889 if (pc == NULL) { 3890 return SOC_E_INTERNAL; 3891 } 3892 pmc = &pc->phymod_ctrl; 3893 3894 for (idx = 0; idx < pmc->num_phys; idx++) { 3895 pm_phy = &pmc->phy[idx]->pm_phy; 3896 SOC_IF_ERROR_RETURN 3897 (phymod_phy_pmd_info_dump(pm_phy, arg)); 3898 } 3899 return (SOC_E_NONE); 3900 } 3901 3902 /* 3903 * phy8806x_tx_lane_squelch 3904 */ 3905 STATIC int 3906 phy8806x_tx_lane_squelch(soc_phymod_ctrl_t *pmc, uint32 value) 3907 { 3908 phymod_phy_access_t *pm_phy; 3909 phymod_phy_tx_lane_control_t tx_control; 3910 int idx; 3911 3912 /* loop through all cores */ 3913 for (idx = 0; idx < pmc->num_phys; idx++) { 3914 pm_phy = &pmc->phy[idx]->pm_phy; 3915 3916 if (pm_phy == NULL) { 3917 return SOC_E_INTERNAL; 3918 } 3919 3920 if (value == 1) { 3921 tx_control = phymodTxSquelchOn; 3922 } else { 3923 tx_control = phymodTxSquelchOff; 3924 } 3925 SOC_IF_ERROR_RETURN 3926 (phymod_phy_tx_lane_control_set(pm_phy, tx_control)); 3927 } 3928 return(SOC_E_NONE); 3929 } 3930 3931 /* 3932 * phy8806x_tx_polarity_set 3933 */ 3934 STATIC int 3935 phy8806x_tx_polarity_set(soc_phymod_ctrl_t *pmc, phymod_polarity_t *cfg_polarity, uint32 value) 3936 { 3937 phymod_phy_access_t *pm_phy; 3938 phymod_polarity_t polarity; 3939 int idx; 3940 3941 /* loop through all cores */ 3942 for (idx = 0; idx < pmc->num_phys; idx++) { 3943 pm_phy = &pmc->phy[idx]->pm_phy; 3944 3945 if (pm_phy == NULL) { 3946 return SOC_E_INTERNAL; 3947 } 3948 3949 sal_memcpy(&polarity, cfg_polarity, sizeof(polarity)); 3950 polarity.tx_polarity = value; 3951 SOC_IF_ERROR_RETURN(phymod_phy_polarity_set(pm_phy, &polarity)); 3952 3953 /* after successfully setting the parity, update the configured value */ 3954 cfg_polarity->tx_polarity = value; 3955 } 3956 3957 return(SOC_E_NONE); 3958 } 3959 3960 /* 3961 * phy8806x_rx_polarity_set 3962 */ 3963 3964 STATIC int 3965 phy8806x_rx_polarity_set(soc_phymod_ctrl_t *pmc, phymod_polarity_t *cfg_polarity, uint32 value) 3966 { 3967 phymod_phy_access_t *pm_phy; 3968 phymod_polarity_t polarity; 3969 int idx; 3970 3971 /* loop through all cores */ 3972 for (idx = 0; idx < pmc->num_phys; idx++) { 3973 pm_phy = &pmc->phy[idx]->pm_phy; 3974 3975 if (pm_phy == NULL) { 3976 return SOC_E_INTERNAL; 3977 } 3978 3979 sal_memcpy(&polarity, cfg_polarity, sizeof(polarity)); 3980 polarity.rx_polarity = value; 3981 SOC_IF_ERROR_RETURN(phymod_phy_polarity_set(pm_phy, &polarity)); 3982 3983 /* after successfully setting the parity, update the configured value */ 3984 cfg_polarity->rx_polarity = value; 3985 } 3986 3987 return(SOC_E_NONE); 3988 } 3989 3990 /* 3991 * phy8806x_rx_reset 3992 */ 3993 STATIC int 3994 phy8806x_rx_reset(soc_phymod_ctrl_t *pmc, phymod_phy_reset_t *cfg_reset, uint32 value) 3995 { 3996 phymod_phy_access_t *pm_phy; 3997 phymod_phy_reset_t reset; 3998 int idx; 3999 4000 /* loop through all cores */ 4001 for (idx = 0; idx < pmc->num_phys; idx++) { 4002 pm_phy = &pmc->phy[idx]->pm_phy; 4003 4004 if (pm_phy == NULL) { 4005 return SOC_E_INTERNAL; 4006 } 4007 4008 sal_memcpy(&reset, cfg_reset, sizeof(reset)); 4009 reset.rx = (phymod_reset_direction_t) value; 4010 SOC_IF_ERROR_RETURN(phymod_phy_reset_set(pm_phy, &reset)); 4011 4012 /* after successfully setting the parity, update the configured value */ 4013 cfg_reset->rx = (phymod_reset_direction_t) value; 4014 } 4015 4016 return(SOC_E_NONE); 4017 } 4018 4019 /* 4020 * phy8806x_tx_reset 4021 */ 4022 STATIC int 4023 phy8806x_tx_reset(soc_phymod_ctrl_t *pmc, phymod_phy_reset_t *cfg_reset, uint32 value) 4024 { 4025 phymod_phy_access_t *pm_phy; 4026 phymod_phy_reset_t reset; 4027 int idx; 4028 4029 /* loop through all cores */ 4030 for (idx = 0; idx < pmc->num_phys; idx++) { 4031 pm_phy = &pmc->phy[idx]->pm_phy; 4032 4033 if (pm_phy == NULL) { 4034 return SOC_E_INTERNAL; 4035 } 4036 4037 sal_memcpy(&reset, cfg_reset, sizeof(reset)); 4038 reset.tx = (phymod_reset_direction_t) value; 4039 SOC_IF_ERROR_RETURN(phymod_phy_reset_set(pm_phy, &reset)); 4040 4041 /* after successfully setting the parity, update the configured value */ 4042 cfg_reset->tx = (phymod_reset_direction_t) value; 4043 } 4044 4045 return(SOC_E_NONE); 4046 } 4047 4048 /* 4049 * phy8806x_cl72_enable_set 4050 */ 4051 STATIC int 4052 phy8806x_cl72_enable_set(soc_phymod_ctrl_t *pmc, uint32 value) 4053 { 4054 phymod_phy_access_t *pm_phy; 4055 int idx; 4056 4057 /* loop through all cores */ 4058 for (idx = 0; idx < pmc->num_phys; idx++) { 4059 pm_phy = &pmc->phy[idx]->pm_phy; 4060 4061 if (pm_phy == NULL) { 4062 return SOC_E_INTERNAL; 4063 } 4064 4065 SOC_IF_ERROR_RETURN(phymod_phy_cl72_set(pm_phy, value)); 4066 } 4067 4068 return(SOC_E_NONE); 4069 } 4070 4071 STATIC int 4072 phy8806x_lane_map_set(soc_phymod_ctrl_t *pmc, uint32 value){ 4073 int idx; 4074 phymod_lane_map_t lane_map; 4075 4076 lane_map.num_of_lanes = NUM_LANES; 4077 if(pmc->phy[0] == NULL){ 4078 return(SOC_E_INTERNAL); 4079 } 4080 for (idx=0; idx < NUM_LANES; idx++) { 4081 lane_map.lane_map_rx[idx] = (value >> (idx * 4 /* 4 bit per lane */)) & 0xf; 4082 } 4083 for (idx=0; idx < NUM_LANES; idx++) { 4084 lane_map.lane_map_tx[idx] = (value >> (16 + idx * 4 /* 4 bit per lane */)) & 0xf; 4085 } 4086 SOC_IF_ERROR_RETURN(phymod_core_lane_map_set(&pmc->phy[0]->core->pm_core, &lane_map)); 4087 return(SOC_E_NONE); 4088 } 4089 4090 /* 4091 * phy8806x_per_lane_prbs_poly_set 4092 */ 4093 int 4094 phy8806x_per_lane_prbs_poly_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value) 4095 { 4096 return(SOC_E_UNAVAIL); 4097 } 4098 4099 STATIC int 4100 phy8806x_sdk_poly_to_phymod_poly(uint32 sdk_poly, phymod_prbs_poly_t *phymod_poly){ 4101 switch(sdk_poly){ 4102 case SOC_PHY_PRBS_POLYNOMIAL_X7_X6_1: 4103 *phymod_poly = phymodPrbsPoly7; 4104 break; 4105 case SOC_PHY_PRBS_POLYNOMIAL_X15_X14_1: 4106 *phymod_poly = phymodPrbsPoly15; 4107 break; 4108 case SOC_PHY_PRBS_POLYNOMIAL_X23_X18_1: 4109 *phymod_poly = phymodPrbsPoly23; 4110 break; 4111 case SOC_PHY_PRBS_POLYNOMIAL_X31_X28_1: 4112 *phymod_poly = phymodPrbsPoly31; 4113 break; 4114 case SOC_PHY_PRBS_POLYNOMIAL_X9_X5_1: 4115 *phymod_poly = phymodPrbsPoly9; 4116 break; 4117 case SOC_PHY_PRBS_POLYNOMIAL_X11_X9_1: 4118 *phymod_poly = phymodPrbsPoly11; 4119 break; 4120 case SOC_PHY_PRBS_POLYNOMIAL_X58_X31_1: 4121 *phymod_poly = phymodPrbsPoly58; 4122 break; 4123 default: 4124 return SOC_E_INTERNAL; 4125 } 4126 return SOC_E_NONE; 4127 } 4128 4129 /* 4130 * phy8806x_prbs_tx_poly_set 4131 */ 4132 int 4133 phy8806x_prbs_tx_poly_set(soc_phymod_ctrl_t *pmc, uint32 value) 4134 { 4135 phymod_phy_access_t *pm_phy; 4136 phymod_prbs_t prbs; 4137 uint32_t flags = 0; 4138 4139 /* just take the value from the first phy */ 4140 if (pmc->phy[0] == NULL) { 4141 return SOC_E_INTERNAL; 4142 } 4143 pm_phy = &pmc->phy[0]->pm_phy; 4144 4145 if (pm_phy == NULL) { 4146 return SOC_E_INTERNAL; 4147 } 4148 PHYMOD_PRBS_DIRECTION_TX_SET(flags); 4149 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs)); 4150 SOC_IF_ERROR_RETURN(phy8806x_sdk_poly_to_phymod_poly(value, &prbs.poly)); 4151 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs)); 4152 return(SOC_E_NONE); 4153 } 4154 4155 /* 4156 * phy8806x_prbs_rx_poly_set 4157 */ 4158 STATIC int 4159 phy8806x_prbs_rx_poly_set(soc_phymod_ctrl_t *pmc, uint32 value) 4160 { 4161 phymod_phy_access_t *pm_phy; 4162 phymod_prbs_t prbs; 4163 uint32_t flags = 0; 4164 4165 /* just take the value from the first phy */ 4166 if (pmc->phy[0] == NULL) { 4167 return SOC_E_INTERNAL; 4168 } 4169 pm_phy = &pmc->phy[0]->pm_phy; 4170 4171 if (pm_phy == NULL) { 4172 return SOC_E_INTERNAL; 4173 } 4174 PHYMOD_PRBS_DIRECTION_RX_SET(flags); 4175 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs)); 4176 SOC_IF_ERROR_RETURN(phy8806x_sdk_poly_to_phymod_poly(value, &prbs.poly)); 4177 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs)); 4178 return(SOC_E_NONE); 4179 } 4180 4181 4182 /* 4183 * phy8806x_per_lane_prbs_tx_invert_data_set 4184 */ 4185 int 4186 phy8806x_per_lane_prbs_tx_invert_data_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value) 4187 { 4188 return(SOC_E_UNAVAIL); 4189 } 4190 4191 /* 4192 * phy8806x_prbs_tx_invert_data_set 4193 */ 4194 STATIC int 4195 phy8806x_prbs_tx_invert_data_set(soc_phymod_ctrl_t *pmc, uint32 value) 4196 { 4197 phymod_phy_access_t *pm_phy; 4198 phymod_prbs_t prbs; 4199 uint32_t flags = 0; 4200 4201 /* just take the value from the first phy */ 4202 if (pmc->phy[0] == NULL) { 4203 return SOC_E_INTERNAL; 4204 } 4205 pm_phy = &pmc->phy[0]->pm_phy; 4206 4207 if (pm_phy == NULL) { 4208 return SOC_E_INTERNAL; 4209 } 4210 4211 PHYMOD_PRBS_DIRECTION_TX_SET(flags); 4212 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs)); 4213 prbs.invert = value; 4214 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs)); 4215 return(SOC_E_NONE); 4216 } 4217 4218 /* 4219 * phy8806x_prbs_rx_invert_data_set 4220 */ 4221 int 4222 phy8806x_prbs_rx_invert_data_set(soc_phymod_ctrl_t *pmc, uint32 value) 4223 { 4224 phymod_phy_access_t *pm_phy; 4225 phymod_prbs_t prbs; 4226 uint32_t flags = 0; 4227 4228 /* just take the value from the first phy */ 4229 if (pmc->phy[0] == NULL) { 4230 return SOC_E_INTERNAL; 4231 } 4232 pm_phy = &pmc->phy[0]->pm_phy; 4233 4234 if (pm_phy == NULL) { 4235 return SOC_E_INTERNAL; 4236 } 4237 4238 PHYMOD_PRBS_DIRECTION_RX_SET(flags); 4239 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_get(pm_phy, flags, &prbs)); 4240 prbs.invert = value; 4241 SOC_IF_ERROR_RETURN(phymod_phy_prbs_config_set(pm_phy, flags, &prbs)); 4242 return(SOC_E_NONE); 4243 } 4244 4245 /* 4246 * phy8806x_per_lane_prbs_tx_enable_set 4247 */ 4248 int 4249 phy8806x_per_lane_prbs_tx_enable_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value) 4250 { 4251 return(SOC_E_UNAVAIL); 4252 } 4253 /* 4254 * phy8806x_prbs_tx_enable_set 4255 */ 4256 STATIC int 4257 phy8806x_prbs_tx_enable_set(soc_phymod_ctrl_t *pmc, uint32 value) 4258 { 4259 phymod_phy_access_t *pm_phy; 4260 uint32_t flags = 0; 4261 4262 /* just take the value from the first phy */ 4263 if (pmc->phy[0] == NULL) { 4264 return SOC_E_INTERNAL; 4265 } 4266 pm_phy = &pmc->phy[0]->pm_phy; 4267 4268 if (pm_phy == NULL) { 4269 return SOC_E_INTERNAL; 4270 } 4271 PHYMOD_PRBS_DIRECTION_TX_SET(flags); 4272 SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_set(pm_phy, flags, value)); 4273 return(SOC_E_NONE); 4274 } 4275 4276 /* 4277 * phy8806x_prbs_rx_enable_set 4278 */ 4279 STATIC int 4280 phy8806x_prbs_rx_enable_set(soc_phymod_ctrl_t *pmc, uint32 value) 4281 { 4282 phymod_phy_access_t *pm_phy; 4283 uint32_t flags = 0; 4284 4285 /* just take the value from the first phy */ 4286 if (pmc->phy[0] == NULL) { 4287 return SOC_E_INTERNAL; 4288 } 4289 pm_phy = &pmc->phy[0]->pm_phy; 4290 4291 if (pm_phy == NULL) { 4292 return SOC_E_INTERNAL; 4293 } 4294 4295 PHYMOD_PRBS_DIRECTION_RX_SET(flags); 4296 SOC_IF_ERROR_RETURN(phymod_phy_prbs_enable_set(pm_phy, flags, value)); 4297 return(SOC_E_NONE); 4298 } 4299 4300 /* 4301 * phy8806x_loopback_internal_set 4302 */ 4303 STATIC int 4304 phy8806x_loopback_internal_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value) 4305 { 4306 phymod_phy_access_t *pm_phy; 4307 #if defined(INCLUDE_FCMAP) 4308 soc_phymod_core_t *core; 4309 phy_ctrl_t *pc; 4310 #endif 4311 phymod_loopback_mode_t lb_mode; 4312 4313 /* just take the value from the first phy */ 4314 if (pmc->phy[0] == NULL) { 4315 return SOC_E_INTERNAL; 4316 } 4317 pm_phy = &pmc->phy[0]->pm_phy; 4318 4319 if (pm_phy == NULL) { 4320 return SOC_E_INTERNAL; 4321 } 4322 4323 if (sys) { 4324 SOC_IF_ERROR_RETURN 4325 (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysGlobal, value)); 4326 } else { 4327 lb_mode = phymodLoopbackGlobal; 4328 #if defined(INCLUDE_FCMAP) 4329 core = pmc->phy[0]->core; 4330 pc = EXT_PHY_SW_STATE(core->unit, core->port); 4331 if (pc->fcmap_enable) { 4332 lb_mode = phymodLoopbackGlobalPMD; 4333 } 4334 #endif 4335 SOC_IF_ERROR_RETURN 4336 (phymod_phy_loopback_set(pm_phy, lb_mode, value)); 4337 4338 } 4339 return(SOC_E_NONE); 4340 } 4341 4342 /* 4343 * phy8806x_loopback_pmd_set 4344 */ 4345 STATIC int 4346 phy8806x_loopback_pmd_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value) 4347 { 4348 phymod_phy_access_t *pm_phy; 4349 4350 /* just take the value from the first phy */ 4351 if (pmc->phy[0] == NULL) { 4352 return SOC_E_INTERNAL; 4353 } 4354 pm_phy = &pmc->phy[0]->pm_phy; 4355 4356 if (pm_phy == NULL) { 4357 return SOC_E_INTERNAL; 4358 } 4359 4360 if (sys) { 4361 SOC_IF_ERROR_RETURN 4362 (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysGlobalPMD, value)); 4363 } else { 4364 SOC_IF_ERROR_RETURN 4365 (phymod_phy_loopback_set(pm_phy, phymodLoopbackGlobalPMD, value)); 4366 } 4367 4368 return(SOC_E_NONE); 4369 } 4370 4371 /* 4372 * phy8806x_loopback_remote_set 4373 */ 4374 STATIC int 4375 phy8806x_loopback_remote_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value) 4376 { 4377 phymod_phy_access_t *pm_phy; 4378 4379 /* just take the value from the first phy */ 4380 if (pmc->phy[0] == NULL) { 4381 return SOC_E_INTERNAL; 4382 } 4383 pm_phy = &pmc->phy[0]->pm_phy; 4384 4385 if (pm_phy == NULL) { 4386 return SOC_E_INTERNAL; 4387 } 4388 4389 if (sys) { 4390 SOC_IF_ERROR_RETURN 4391 (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysRemotePMD, value)); 4392 } else { 4393 SOC_IF_ERROR_RETURN 4394 (phymod_phy_loopback_set(pm_phy, phymodLoopbackRemotePMD, value)); 4395 } 4396 return(SOC_E_NONE); 4397 } 4398 4399 /* 4400 * phy8806x_loopback_pcs_set 4401 */ 4402 /* STATIC */ int 4403 phy8806x_loopback_pcs_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value) 4404 { 4405 phymod_phy_access_t *pm_phy; 4406 4407 /* just take the value from the first phy */ 4408 if (pmc->phy[0] == NULL) { 4409 return SOC_E_INTERNAL; 4410 } 4411 pm_phy = &pmc->phy[0]->pm_phy; 4412 4413 if (pm_phy == NULL) { 4414 return SOC_E_INTERNAL; 4415 } 4416 4417 if (sys) { 4418 SOC_IF_ERROR_RETURN 4419 (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysGlobalPCS, value)); 4420 } else { 4421 SOC_IF_ERROR_RETURN 4422 (phymod_phy_loopback_set(pm_phy, phymodLoopbackGlobalPCS, value)); 4423 } 4424 4425 return(SOC_E_NONE); 4426 } 4427 4428 /* 4429 * phy8806x_loopback_remote_pcs_set 4430 */ 4431 STATIC int 4432 phy8806x_loopback_remote_pcs_set(soc_phymod_ctrl_t *pmc, int sys, uint32 value) 4433 { 4434 phymod_phy_access_t *pm_phy; 4435 4436 /* just take the value from the first phy */ 4437 if (pmc->phy[0] == NULL) { 4438 return SOC_E_INTERNAL; 4439 } 4440 pm_phy = &pmc->phy[0]->pm_phy; 4441 4442 if (pm_phy == NULL) { 4443 return SOC_E_INTERNAL; 4444 } 4445 4446 if (sys) { 4447 SOC_IF_ERROR_RETURN 4448 (phymod_phy_loopback_set(pm_phy, phymodLoopbackSysRemotePCS, value)); 4449 } else { 4450 SOC_IF_ERROR_RETURN 4451 (phymod_phy_loopback_set(pm_phy, phymodLoopbackRemotePCS, value)); 4452 } 4453 4454 return(SOC_E_NONE); 4455 } 4456 4457 /* 4458 * phy8806x_fec_enable_set 4459 */ 4460 STATIC int 4461 phy8806x_fec_enable_set(soc_phymod_ctrl_t *pmc, uint32 value) 4462 { 4463 phymod_phy_access_t *pm_phy; 4464 int idx; 4465 4466 /* loop through all cores */ 4467 for (idx = 0; idx < pmc->num_phys; idx++) { 4468 pm_phy = &pmc->phy[idx]->pm_phy; 4469 4470 if (pm_phy == NULL) { 4471 return SOC_E_INTERNAL; 4472 } 4473 SOC_IF_ERROR_RETURN(phymod_phy_fec_enable_set(pm_phy, value)); 4474 } 4475 return(SOC_E_NONE); 4476 } 4477 4478 /* 4479 * phy8806x_power_set 4480 */ 4481 STATIC int 4482 phy8806x_power_set(soc_phymod_ctrl_t *pmc, uint32 value) 4483 { 4484 phymod_phy_access_t *pm_phy; 4485 phymod_phy_power_t power; 4486 int idx; 4487 4488 /* loop through all cores */ 4489 for (idx = 0; idx < pmc->num_phys; idx++) { 4490 pm_phy = &pmc->phy[idx]->pm_phy; 4491 4492 if (pm_phy == NULL) { 4493 return SOC_E_INTERNAL; 4494 } 4495 4496 phymod_phy_power_t_init(&power); 4497 if (value) { 4498 power.tx = phymodPowerOn; 4499 power.rx = phymodPowerOn; 4500 } 4501 else { 4502 power.tx = phymodPowerOff; 4503 power.rx = phymodPowerOff; 4504 } 4505 4506 SOC_IF_ERROR_RETURN(phymod_phy_power_set(pm_phy, &power)); 4507 } 4508 4509 return(SOC_E_NONE); 4510 } 4511 4512 /* 4513 * given a pc (phymod_ctrl_t) and logical lane number, 4514 * find the correct soc_phymod_phy_t object and lane 4515 */ 4516 STATIC int 4517 _phy8806x_find_soc_phy_lane(soc_phymod_ctrl_t *pmc, uint32_t lane, 4518 soc_phymod_phy_t **p_phy, uint32 *lane_map) 4519 { 4520 phymod_phy_access_t *pm_phy; 4521 int idx, lnx, ln_cnt, found; 4522 uint32 lane_map_copy; 4523 4524 /* Traverse lanes belonging to this port */ 4525 found = 0; 4526 ln_cnt = 0; 4527 for (idx = 0; idx < pmc->num_phys; idx++) { 4528 pm_phy = &pmc->phy[idx]->pm_phy; 4529 if (pm_phy == NULL) { 4530 return SOC_E_INTERNAL; 4531 } 4532 lane_map_copy = pm_phy->access.lane_mask; 4533 for (lnx = 0; lnx < 4; lnx++) { 4534 if ((1 << lnx) & lane_map_copy) { 4535 if (ln_cnt == lane) { 4536 found = 1; 4537 break; 4538 } 4539 ln_cnt++; 4540 } 4541 } 4542 if (found) { 4543 *p_phy = pmc->phy[idx]; 4544 *lane_map = (1 << lnx); 4545 break; 4546 } 4547 } 4548 4549 if (!found) { 4550 /* No such lane */ 4551 return SOC_E_PARAM; 4552 } 4553 return (SOC_E_NONE); 4554 } 4555 4556 4557 /* 4558 * phy8806x_per_lane_preemphasis_set 4559 */ 4560 STATIC int 4561 phy8806x_per_lane_preemphasis_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value) 4562 { 4563 soc_phymod_phy_t *p_phy; 4564 uint32 lane_map; 4565 phymod_phy_access_t pm_phy_copy, *pm_phy; 4566 phymod_tx_t phymod_tx; 4567 soc_phymod_core_t *soc_core; 4568 4569 /* locate the desired phy and lane */ 4570 SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 4571 4572 /* Make a copy of the phy access and overwrite the desired lane */ 4573 pm_phy = &p_phy->pm_phy; 4574 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4575 pm_phy_copy.access.lane_mask = lane_map; 4576 4577 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4578 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4579 4580 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4581 phymod_tx.pre = value & 0xff; 4582 phymod_tx.main = (value >> 8) & 0xff; 4583 phymod_tx.post = (value >> 16) & 0xff; 4584 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4585 4586 return(SOC_E_NONE); 4587 } 4588 4589 /* 4590 * phy8806x_preemphasis_set 4591 */ 4592 STATIC int 4593 phy8806x_preemphasis_set(soc_phymod_ctrl_t *pmc, uint32 value) 4594 { 4595 phymod_phy_access_t *pm_phy, pm_phy_copy; 4596 phymod_tx_t phymod_tx; 4597 int idx; 4598 soc_phymod_core_t *soc_core; 4599 4600 /* loop through all cores */ 4601 for (idx = 0; idx < pmc->num_phys; idx++) { 4602 pm_phy = &pmc->phy[idx]->pm_phy; 4603 4604 if (pm_phy == NULL) { 4605 return SOC_E_INTERNAL; 4606 } 4607 4608 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4609 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4610 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4611 4612 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4613 phymod_tx.pre = value & 0xff; 4614 phymod_tx.main = (value >> 8) & 0xff; 4615 phymod_tx.post = (value >> 16) & 0xff; 4616 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4617 } 4618 4619 return(SOC_E_NONE); 4620 } 4621 4622 /* 4623 * phy8806x_tx_fir_pre_set 4624 */ 4625 STATIC int 4626 phy8806x_tx_fir_pre_set(soc_phymod_ctrl_t *pmc, uint32 value) 4627 { 4628 phymod_phy_access_t *pm_phy, pm_phy_copy; 4629 phymod_tx_t phymod_tx; 4630 int idx; 4631 soc_phymod_core_t *soc_core; 4632 4633 /* loop through all cores */ 4634 for (idx = 0; idx < pmc->num_phys; idx++) { 4635 pm_phy = &pmc->phy[idx]->pm_phy; 4636 4637 if (pm_phy == NULL) { 4638 return SOC_E_INTERNAL; 4639 } 4640 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4641 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4642 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4643 4644 4645 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4646 phymod_tx.pre = value; 4647 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4648 } 4649 4650 return(SOC_E_NONE); 4651 } 4652 4653 /* 4654 * phy8806x_tx_fir_main_set 4655 */ 4656 STATIC int 4657 phy8806x_tx_fir_main_set(soc_phymod_ctrl_t *pmc, uint32 value) 4658 { 4659 phymod_phy_access_t *pm_phy, pm_phy_copy; 4660 phymod_tx_t phymod_tx; 4661 int idx; 4662 soc_phymod_core_t *soc_core; 4663 4664 /* loop through all cores */ 4665 for (idx = 0; idx < pmc->num_phys; idx++) { 4666 pm_phy = &pmc->phy[idx]->pm_phy; 4667 4668 if (pm_phy == NULL) { 4669 return SOC_E_INTERNAL; 4670 } 4671 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4672 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4673 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4674 4675 4676 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4677 phymod_tx.main = value; 4678 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4679 } 4680 4681 return(SOC_E_NONE); 4682 } 4683 4684 /* 4685 * phy8806x_tx_fir_post_set 4686 */ 4687 STATIC int 4688 phy8806x_tx_fir_post_set(soc_phymod_ctrl_t *pmc, uint32 value) 4689 { 4690 phymod_phy_access_t *pm_phy, pm_phy_copy; 4691 phymod_tx_t phymod_tx; 4692 int idx; 4693 soc_phymod_core_t *soc_core; 4694 4695 /* loop through all cores */ 4696 for (idx = 0; idx < pmc->num_phys; idx++) { 4697 pm_phy = &pmc->phy[idx]->pm_phy; 4698 4699 if (pm_phy == NULL) { 4700 return SOC_E_INTERNAL; 4701 } 4702 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4703 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4704 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4705 4706 4707 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4708 phymod_tx.post = value; 4709 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4710 } 4711 4712 return(SOC_E_NONE); 4713 } 4714 4715 /* 4716 * phy8806x_tx_fir_post2_set 4717 */ 4718 STATIC int 4719 phy8806x_tx_fir_post2_set(soc_phymod_ctrl_t *pmc, uint32 value) 4720 { 4721 phymod_phy_access_t *pm_phy, pm_phy_copy; 4722 phymod_tx_t phymod_tx; 4723 int idx; 4724 soc_phymod_core_t *soc_core; 4725 4726 /* loop through all cores */ 4727 for (idx = 0; idx < pmc->num_phys; idx++) { 4728 pm_phy = &pmc->phy[idx]->pm_phy; 4729 4730 if (pm_phy == NULL) { 4731 return SOC_E_INTERNAL; 4732 } 4733 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4734 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4735 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4736 4737 4738 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4739 phymod_tx.post2 = value; 4740 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4741 } 4742 4743 return(SOC_E_NONE); 4744 } 4745 4746 /* 4747 * phy8806x_tx_fir_post3_set 4748 */ 4749 STATIC int 4750 phy8806x_tx_fir_post3_set(soc_phymod_ctrl_t *pmc, uint32 value) 4751 { 4752 phymod_phy_access_t *pm_phy, pm_phy_copy; 4753 phymod_tx_t phymod_tx; 4754 int idx; 4755 soc_phymod_core_t *soc_core; 4756 4757 /* loop through all cores */ 4758 for (idx = 0; idx < pmc->num_phys; idx++) { 4759 pm_phy = &pmc->phy[idx]->pm_phy; 4760 4761 if (pm_phy == NULL) { 4762 return SOC_E_INTERNAL; 4763 } 4764 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4765 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4766 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4767 4768 4769 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4770 phymod_tx.post3 = value; 4771 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4772 } 4773 4774 return(SOC_E_NONE); 4775 } 4776 4777 /* 4778 * phy8806x_per_lane_driver_current_set 4779 */ 4780 STATIC int 4781 phy8806x_per_lane_driver_current_set(soc_phymod_ctrl_t *pmc, int lane, uint32 value) 4782 { 4783 soc_phymod_phy_t *p_phy; 4784 uint32 lane_map; 4785 phymod_phy_access_t pm_phy_copy, *pm_phy; 4786 phymod_tx_t phymod_tx; 4787 soc_phymod_core_t *soc_core; 4788 4789 /* locate the desired phy and lane */ 4790 SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 4791 4792 /* Make a copy of the phy access and overwrite the desired lane */ 4793 pm_phy = &p_phy->pm_phy; 4794 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4795 pm_phy_copy.access.lane_mask = lane_map; 4796 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4797 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4798 4799 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4800 phymod_tx.amp = value; 4801 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4802 4803 return(SOC_E_NONE); 4804 } 4805 4806 4807 /* 4808 * phy8806x_driver_current_set 4809 */ 4810 STATIC int 4811 phy8806x_driver_current_set(soc_phymod_ctrl_t *pmc, uint32 value) 4812 { 4813 phymod_phy_access_t *pm_phy, pm_phy_copy; 4814 phymod_tx_t phymod_tx; 4815 int idx; 4816 soc_phymod_core_t *soc_core; 4817 4818 /* loop through all cores */ 4819 for (idx = 0; idx < pmc->num_phys; idx++) { 4820 pm_phy = &pmc->phy[idx]->pm_phy; 4821 4822 if (pm_phy == NULL) { 4823 return SOC_E_INTERNAL; 4824 } 4825 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4826 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4827 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4828 4829 4830 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 4831 phymod_tx.amp = value; 4832 SOC_IF_ERROR_RETURN(phymod_phy_tx_set(&pm_phy_copy, &phymod_tx)); 4833 } 4834 4835 return(SOC_E_NONE); 4836 } 4837 4838 STATIC int 4839 phy8806x_firmware_unreliable_los_set(soc_phymod_ctrl_t *pmc, uint32 enable) 4840 { 4841 phymod_phy_access_t pm_phy_copy, *pm_phy; 4842 phymod_firmware_lane_config_t fw_config; 4843 int idx; 4844 soc_phymod_core_t *soc_core; 4845 4846 /* loop through all cores */ 4847 for (idx = 0; idx < pmc->num_phys; idx++) { 4848 if (pmc->phy[idx] == NULL) { 4849 return(SOC_E_INTERNAL); 4850 } 4851 4852 pm_phy = &pmc->phy[idx]->pm_phy; 4853 if (pm_phy == NULL) { 4854 return(SOC_E_INTERNAL); 4855 } 4856 4857 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4858 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4859 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4860 4861 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 4862 4863 if (enable) { 4864 fw_config.UnreliableLos = 1; 4865 } else { 4866 fw_config.UnreliableLos = 0; 4867 } 4868 4869 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config)); 4870 } 4871 4872 return(SOC_E_NONE); 4873 } 4874 4875 4876 STATIC int 4877 phy8806x_firmware_dfe_enable_set(soc_phymod_ctrl_t *pmc, uint32 enable) 4878 { 4879 phymod_phy_access_t pm_phy_copy, *pm_phy; 4880 phymod_firmware_lane_config_t fw_config; 4881 int idx; 4882 soc_phymod_core_t *soc_core; 4883 4884 /* loop through all cores */ 4885 for (idx = 0; idx < pmc->num_phys; idx++) { 4886 if (pmc->phy[idx] == NULL) { 4887 return(SOC_E_INTERNAL); 4888 } 4889 4890 pm_phy = &pmc->phy[idx]->pm_phy; 4891 if (pm_phy == NULL) { 4892 return(SOC_E_INTERNAL); 4893 } 4894 4895 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4896 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4897 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4898 4899 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 4900 4901 if (enable) { 4902 fw_config.DfeOn = 1; 4903 } else { 4904 fw_config.DfeOn = 0; 4905 } 4906 4907 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config)); 4908 } 4909 4910 return(SOC_E_NONE); 4911 } 4912 4913 /* 4914 * tscf_firmware_mode_set 4915 */ 4916 STATIC int 4917 phy8806x_firmware_lp_dfe_enable_set(soc_phymod_ctrl_t *pmc, uint32 enable) 4918 { 4919 phymod_phy_access_t pm_phy_copy, *pm_phy; 4920 phymod_firmware_lane_config_t fw_config; 4921 int idx; 4922 soc_phymod_core_t *soc_core; 4923 4924 /* loop through all cores */ 4925 for (idx = 0; idx < pmc->num_phys; idx++) { 4926 if (pmc->phy[idx] == NULL) { 4927 return(SOC_E_INTERNAL); 4928 } 4929 4930 pm_phy = &pmc->phy[idx]->pm_phy; 4931 if (pm_phy == NULL) { 4932 return(SOC_E_INTERNAL); 4933 } 4934 4935 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4936 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4937 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4938 4939 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 4940 4941 if (enable) { 4942 fw_config.DfeOn = 1; 4943 fw_config.LpDfeOn = 1; 4944 } else { 4945 fw_config.LpDfeOn = 0; 4946 } 4947 4948 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config)); 4949 } 4950 4951 return(SOC_E_NONE); 4952 } 4953 4954 STATIC int 4955 phy8806x_firmware_br_dfe_enable_set(soc_phymod_ctrl_t *pmc, uint32 enable) 4956 { 4957 phymod_phy_access_t pm_phy_copy, *pm_phy; 4958 phymod_firmware_lane_config_t fw_config; 4959 int idx; 4960 soc_phymod_core_t *soc_core; 4961 4962 /* loop through all cores */ 4963 for (idx = 0; idx < pmc->num_phys; idx++) { 4964 if (pmc->phy[idx] == NULL) { 4965 return(SOC_E_INTERNAL); 4966 } 4967 4968 pm_phy = &pmc->phy[idx]->pm_phy; 4969 if (pm_phy == NULL) { 4970 return(SOC_E_INTERNAL); 4971 } 4972 4973 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 4974 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 4975 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 4976 4977 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 4978 4979 if (enable) { 4980 fw_config.DfeOn = 1; 4981 fw_config.ForceBrDfe = 1; 4982 } else { 4983 fw_config.ForceBrDfe = 0; 4984 } 4985 4986 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_set(&pm_phy_copy, fw_config)); 4987 } 4988 4989 return(SOC_E_NONE); 4990 } 4991 4992 /* 4993 * Function: 4994 * phy_8806x_control_set 4995 * Purpose: 4996 * Configure PHY device specific control fucntion. 4997 * Parameters: 4998 * unit - BCM unit number. 4999 * port - Port number. 5000 * type - Control to update 5001 * value - New setting for the control 5002 * Returns: 5003 * SOC_E_NONE 5004 */ 5005 STATIC int 5006 phy_8806x_control_set(int unit, soc_port_t port, soc_phy_control_t type, uint32 value) 5007 { 5008 int rv; 5009 phy_ctrl_t *pc; 5010 soc_phymod_ctrl_t *pmc; 5011 phy8806x_config_t *pCfg; 5012 5013 rv = SOC_E_UNAVAIL; 5014 5015 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 5016 return (SOC_E_PARAM); 5017 } 5018 5019 /* locate phy control, phymod control, and the configuration data */ 5020 pc = EXT_PHY_SW_STATE(unit, port); 5021 if (pc == NULL) { 5022 return SOC_E_INTERNAL; 5023 } 5024 5025 #if defined(INCLUDE_FCMAP) 5026 /* Skip these loopback set for FC */ 5027 if ((pc->fcmap_enable) && 5028 (type == SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS)) { 5029 return SOC_E_NONE; 5030 } 5031 #endif 5032 5033 pmc = &pc->phymod_ctrl; 5034 pCfg = (phy8806x_config_t *) pc->driver_data; 5035 5036 switch(type) { 5037 case SOC_PHY_CONTROL_UNRELIABLE_LOS: 5038 rv = phy8806x_firmware_unreliable_los_set(pmc, value); 5039 break; 5040 case SOC_PHY_CONTROL_FIRMWARE_DFE_ENABLE: 5041 rv = phy8806x_firmware_dfe_enable_set(pmc, value); 5042 break; 5043 case SOC_PHY_CONTROL_FIRMWARE_LP_DFE_ENABLE: 5044 rv = phy8806x_firmware_lp_dfe_enable_set(pmc, value); 5045 break; 5046 case SOC_PHY_CONTROL_FIRMWARE_BR_DFE_ENABLE: 5047 rv = phy8806x_firmware_br_dfe_enable_set(pmc, value); 5048 break; 5049 5050 /* TX LANE SQUELCH */ 5051 case SOC_PHY_CONTROL_TX_LANE_SQUELCH: 5052 rv = phy8806x_tx_lane_squelch(pmc, value); 5053 break; 5054 5055 /* POLARITY */ 5056 case SOC_PHY_CONTROL_RX_POLARITY: 5057 rv = phy8806x_rx_polarity_set(pmc, &pCfg->phy_polarity_config, value);; 5058 break; 5059 case SOC_PHY_CONTROL_TX_POLARITY: 5060 rv = phy8806x_tx_polarity_set(pmc, &pCfg->phy_polarity_config, value); 5061 break; 5062 5063 /* RESET */ 5064 case SOC_PHY_CONTROL_RX_RESET: 5065 rv = phy8806x_rx_reset(pmc, &pCfg->phy_reset_config, value); 5066 break; 5067 case SOC_PHY_CONTROL_TX_RESET: 5068 rv = phy8806x_tx_reset(pmc, &pCfg->phy_reset_config, value); 5069 break; 5070 5071 /* CL72 ENABLE */ 5072 case SOC_PHY_CONTROL_CL72: 5073 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 5074 value = value | PORT_SYS_SIDE_CTRL; 5075 } 5076 rv = phy8806x_cl72_enable_set(pmc, value); 5077 break; 5078 5079 /* LANE SWAP */ 5080 case SOC_PHY_CONTROL_LANE_SWAP: 5081 rv = phy8806x_lane_map_set(pmc, value); 5082 break; 5083 5084 /* for legacy prbs usage mainly set both tx/rx the same */ 5085 case SOC_PHY_CONTROL_PRBS_POLYNOMIAL: 5086 rv = phy8806x_prbs_tx_poly_set(pmc, value); 5087 rv = phy8806x_prbs_rx_poly_set(pmc, value); 5088 break; 5089 case SOC_PHY_CONTROL_PRBS_TX_INVERT_DATA: 5090 rv = phy8806x_prbs_tx_invert_data_set(pmc, value); 5091 break; 5092 case SOC_PHY_CONTROL_PRBS_TX_ENABLE: 5093 rv = phy8806x_prbs_tx_enable_set(pmc, value); 5094 rv = phy8806x_prbs_rx_enable_set(pmc, value); 5095 break; 5096 case SOC_PHY_CONTROL_PRBS_RX_ENABLE: 5097 rv = phy8806x_prbs_tx_enable_set(pmc, value); 5098 rv = phy8806x_prbs_rx_enable_set(pmc, value); 5099 break; 5100 5101 /* LOOPBACK */ 5102 case SOC_PHY_CONTROL_LOOPBACK_INTERNAL: 5103 rv = phy8806x_loopback_internal_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 5104 break; 5105 case SOC_PHY_CONTROL_LOOPBACK_PMD: 5106 rv = phy8806x_loopback_pmd_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 5107 break; 5108 case SOC_PHY_CONTROL_LOOPBACK_REMOTE: 5109 rv = phy8806x_loopback_remote_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 5110 break; 5111 case SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS: 5112 rv = phy8806x_loopback_remote_pcs_set(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 5113 break; 5114 5115 /* FEC */ 5116 case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION: 5117 if (value) /* 1 for CL74 */ 5118 value = 1; 5119 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 5120 value = value | PORT_SYS_SIDE_CTRL; 5121 } 5122 rv = phy8806x_fec_enable_set(pmc, value); 5123 break; 5124 5125 case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91: 5126 if (value) 5127 value = 2; /* 1 for CL74, 2 for Cl91 */ 5128 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 5129 value = value | PORT_SYS_SIDE_CTRL; 5130 } 5131 rv = phy8806x_fec_enable_set(pmc, value); 5132 break; 5133 5134 /* POWER */ 5135 case SOC_PHY_CONTROL_POWER: 5136 rv = phy8806x_power_set(pmc, value); 5137 break; 5138 5139 case SOC_PHY_CONTROL_FORCED_SPEED_LINE_SIDE: 5140 if (pCfg->speed_config.port_mode == ETH_ETHERRAM) 5141 rv = phy8806x_forced_speed_line_side_set(pmc, value); 5142 else 5143 rv = SOC_E_UNAVAIL; 5144 break; 5145 case SOC_PHY_CONTROL_AUTONEG_LINE_SIDE: 5146 if (pCfg->speed_config.port_mode == ETH_ETHERRAM) 5147 rv = phy8806x_autoneg_line_side_set(pmc, value); 5148 else 5149 rv = SOC_E_UNAVAIL; 5150 break; 5151 case SOC_PHY_CONTROL_EGRESS_FLOW_CONTROL_MODE: 5152 if (pCfg->speed_config.port_mode == ETH_ETHERRAM) 5153 rv = phy8806x_flow_control_mode_set(pmc, value, 0); 5154 else 5155 rv = SOC_E_UNAVAIL; 5156 break; 5157 case SOC_PHY_CONTROL_INGRESS_FLOW_CONTROL_MODE: 5158 if (pCfg->speed_config.port_mode == ETH_ETHERRAM) 5159 rv = phy8806x_flow_control_mode_set(pmc, value, 1); 5160 else 5161 rv = SOC_E_UNAVAIL; 5162 break; 5163 case SOC_PHY_CONTROL_PSM_COS_BMP: 5164 if (pCfg->speed_config.port_mode == ETH_ETHERRAM) 5165 rv = phy8806x_psm_cos_bmp_set(pmc, value); 5166 else 5167 rv = SOC_E_UNAVAIL; 5168 break; 5169 case SOC_PHY_CONTROL_PFC_USE_IP_COS: 5170 if (pCfg->speed_config.port_mode == ETH_ETHERRAM) { 5171 rv = phy8806x_pfc_use_ip_cos_set(pmc, value); 5172 } else { 5173 rv = SOC_E_UNAVAIL; 5174 } 5175 break; 5176 case SOC_PHY_CONTROL_TX_FIR_PRE: 5177 rv = phy8806x_tx_fir_pre_set(pmc, value); 5178 break; 5179 case SOC_PHY_CONTROL_TX_FIR_MAIN: 5180 rv = phy8806x_tx_fir_main_set(pmc, value); 5181 break; 5182 case SOC_PHY_CONTROL_TX_FIR_POST: 5183 rv = phy8806x_tx_fir_post_set(pmc, value); 5184 break; 5185 case SOC_PHY_CONTROL_TX_FIR_POST2: 5186 rv = phy8806x_tx_fir_post2_set(pmc, value); 5187 break; 5188 case SOC_PHY_CONTROL_TX_FIR_POST3: 5189 rv = phy8806x_tx_fir_post3_set(pmc, value); 5190 break; 5191 /* PREEMPHASIS */ 5192 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 5193 rv = phy8806x_per_lane_preemphasis_set(pmc, 0, value); 5194 break; 5195 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 5196 rv = phy8806x_per_lane_preemphasis_set(pmc, 1, value); 5197 break; 5198 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 5199 rv = phy8806x_per_lane_preemphasis_set(pmc, 2, value); 5200 break; 5201 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 5202 rv = phy8806x_per_lane_preemphasis_set(pmc, 3, value); 5203 break; 5204 case SOC_PHY_CONTROL_PREEMPHASIS: 5205 { 5206 /* we need to check if the value is 0xffffff, if yes, then clear 5207 the user_set_tx bit */ 5208 if (value == 0xffffff) { 5209 pCfg->user_set_tx = 0; 5210 } else { 5211 rv = phy8806x_preemphasis_set(pmc, value); 5212 } 5213 break; 5214 } 5215 /* DRIVER CURRENT */ 5216 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 5217 rv = phy8806x_per_lane_driver_current_set(pmc, 0, value); 5218 break; 5219 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 5220 rv = phy8806x_per_lane_driver_current_set(pmc, 1, value); 5221 break; 5222 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 5223 rv = phy8806x_per_lane_driver_current_set(pmc, 2, value); 5224 break; 5225 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 5226 rv = phy8806x_per_lane_driver_current_set(pmc, 3, value); 5227 break; 5228 case SOC_PHY_CONTROL_DRIVER_CURRENT: 5229 rv = phy8806x_driver_current_set(pmc, value); 5230 break; 5231 case SOC_PHY_CONTROL_INTERFACE: 5232 rv = phy_8806x_interface_set(unit, port, value); 5233 break; 5234 default: 5235 rv = SOC_E_UNAVAIL; 5236 break; 5237 } 5238 return rv; 5239 } 5240 5241 STATIC int 5242 phy8806x_pfc_use_ip_cos_set(soc_phymod_ctrl_t *pmc, uint32 value) 5243 { 5244 phymod_phy_access_t *pm_phy; 5245 int idx; 5246 5247 /* loop through all cores */ 5248 for (idx = 0; idx < pmc->num_phys; idx++) { 5249 pm_phy = &pmc->phy[idx]->pm_phy; 5250 5251 if (pm_phy == NULL) { 5252 return SOC_E_INTERNAL; 5253 } 5254 SOC_IF_ERROR_RETURN(phymod_phy_pfc_use_ip_cos_set(pm_phy, value)); 5255 } 5256 return(SOC_E_NONE); 5257 } 5258 5259 STATIC int 5260 phy8806x_pfc_use_ip_cos_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5261 { 5262 phymod_phy_access_t *pm_phy; 5263 int idx; 5264 5265 /* loop through all cores */ 5266 for (idx = 0; idx < pmc->num_phys; idx++) { 5267 pm_phy = &pmc->phy[idx]->pm_phy; 5268 5269 if (pm_phy == NULL) { 5270 return SOC_E_INTERNAL; 5271 } 5272 SOC_IF_ERROR_RETURN(phymod_phy_pfc_use_ip_cos_get(pm_phy, value)); 5273 } 5274 5275 return(SOC_E_NONE); 5276 } 5277 5278 STATIC int 5279 phy8806x_psm_cos_bmp_set(soc_phymod_ctrl_t *pmc, uint32 value) 5280 { 5281 phymod_phy_access_t *pm_phy; 5282 int idx; 5283 5284 /* loop through all cores */ 5285 for (idx = 0; idx < pmc->num_phys; idx++) { 5286 pm_phy = &pmc->phy[idx]->pm_phy; 5287 5288 if (pm_phy == NULL) { 5289 return SOC_E_INTERNAL; 5290 } 5291 SOC_IF_ERROR_RETURN(phymod_phy_psm_cos_bmp_set(pm_phy, value)); 5292 } 5293 return(SOC_E_NONE); 5294 } 5295 5296 STATIC int 5297 phy8806x_psm_cos_bmp_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5298 { 5299 phymod_phy_access_t *pm_phy; 5300 int idx; 5301 5302 /* loop through all cores */ 5303 for (idx = 0; idx < pmc->num_phys; idx++) { 5304 pm_phy = &pmc->phy[idx]->pm_phy; 5305 5306 if (pm_phy == NULL) { 5307 return SOC_E_INTERNAL; 5308 } 5309 SOC_IF_ERROR_RETURN(phymod_phy_psm_cos_bmp_get(pm_phy, value)); 5310 } 5311 5312 return(SOC_E_NONE); 5313 } 5314 5315 STATIC int 5316 phy8806x_flow_control_mode_set(soc_phymod_ctrl_t *pmc, uint32 value, uint8 ingress) 5317 { 5318 phymod_phy_access_t *pm_phy; 5319 int idx; 5320 5321 /* loop through all cores */ 5322 for (idx = 0; idx < pmc->num_phys; idx++) { 5323 pm_phy = &pmc->phy[idx]->pm_phy; 5324 5325 if (pm_phy == NULL) { 5326 return SOC_E_INTERNAL; 5327 } 5328 SOC_IF_ERROR_RETURN(phymod_phy_flow_control_mode_set(pm_phy, value, ingress)); 5329 } 5330 return(SOC_E_NONE); 5331 } 5332 5333 STATIC int 5334 phy8806x_flow_control_mode_get(soc_phymod_ctrl_t *pmc, uint8 ingress, uint32 *value) 5335 { 5336 phymod_phy_access_t *pm_phy; 5337 int idx; 5338 5339 /* loop through all cores */ 5340 for (idx = 0; idx < pmc->num_phys; idx++) { 5341 pm_phy = &pmc->phy[idx]->pm_phy; 5342 5343 if (pm_phy == NULL) { 5344 return SOC_E_INTERNAL; 5345 } 5346 SOC_IF_ERROR_RETURN(phymod_phy_flow_control_mode_get(pm_phy, ingress, value)); 5347 } 5348 5349 return(SOC_E_NONE); 5350 } 5351 5352 STATIC int 5353 phy8806x_forced_speed_line_side_set(soc_phymod_ctrl_t *pmc, uint32 value) 5354 { 5355 phymod_phy_access_t *pm_phy; 5356 int idx; 5357 5358 /* loop through all cores */ 5359 for (idx = 0; idx < pmc->num_phys; idx++) { 5360 pm_phy = &pmc->phy[idx]->pm_phy; 5361 5362 if (pm_phy == NULL) { 5363 return SOC_E_INTERNAL; 5364 } 5365 SOC_IF_ERROR_RETURN(phymod_phy_forced_speed_line_side_set(pm_phy, value)); 5366 } 5367 5368 return(SOC_E_NONE); 5369 } 5370 5371 STATIC int 5372 phy8806x_forced_speed_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5373 { 5374 phymod_phy_access_t *pm_phy; 5375 int idx; 5376 5377 /* loop through all cores */ 5378 for (idx = 0; idx < pmc->num_phys; idx++) { 5379 pm_phy = &pmc->phy[idx]->pm_phy; 5380 5381 if (pm_phy == NULL) { 5382 return SOC_E_INTERNAL; 5383 } 5384 SOC_IF_ERROR_RETURN(phymod_phy_forced_speed_line_side_get(pm_phy, value)); 5385 } 5386 5387 return(SOC_E_NONE); 5388 } 5389 5390 5391 STATIC int 5392 phy8806x_autoneg_line_side_set(soc_phymod_ctrl_t *pmc, uint32 value) 5393 { 5394 phymod_phy_access_t *pm_phy; 5395 int idx; 5396 5397 /* loop through all cores */ 5398 for (idx = 0; idx < pmc->num_phys; idx++) { 5399 pm_phy = &pmc->phy[idx]->pm_phy; 5400 5401 if (pm_phy == NULL) { 5402 return SOC_E_INTERNAL; 5403 } 5404 SOC_IF_ERROR_RETURN(phymod_phy_autoneg_line_side_set(pm_phy, value)); 5405 } 5406 5407 5408 return(SOC_E_NONE); 5409 } 5410 5411 STATIC int 5412 phy8806x_autoneg_line_side_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5413 { 5414 phymod_phy_access_t *pm_phy; 5415 int idx; 5416 5417 /* loop through all cores */ 5418 for (idx = 0; idx < pmc->num_phys; idx++) { 5419 pm_phy = &pmc->phy[idx]->pm_phy; 5420 5421 if (pm_phy == NULL) { 5422 return SOC_E_INTERNAL; 5423 } 5424 SOC_IF_ERROR_RETURN(phymod_phy_autoneg_line_side_get(pm_phy, value)); 5425 } 5426 5427 return(SOC_E_NONE); 5428 } 5429 5430 /* 5431 * phy8806x_cl72_enable_get 5432 */ 5433 STATIC int 5434 phy8806x_cl72_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5435 { 5436 phymod_phy_access_t *pm_phy; 5437 5438 /* just take the value from the first phy */ 5439 if (pmc->phy[0] == NULL) { 5440 return SOC_E_INTERNAL; 5441 } 5442 pm_phy = &pmc->phy[0]->pm_phy; 5443 5444 if (pm_phy == NULL) { 5445 return SOC_E_INTERNAL; 5446 } 5447 5448 SOC_IF_ERROR_RETURN(phymod_phy_cl72_get(pm_phy, value)); 5449 5450 return(SOC_E_NONE); 5451 } 5452 5453 /* 5454 * phy8806x_cl72_status_get 5455 */ 5456 STATIC int 5457 phy8806x_cl72_status_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5458 { 5459 phymod_phy_access_t *pm_phy; 5460 phymod_cl72_status_t status; 5461 phymod_phy_access_t pm_phy_copy; 5462 soc_phymod_core_t *soc_core; 5463 5464 /* just take the value from the first phy */ 5465 if (pmc->phy[0] == NULL) { 5466 return SOC_E_INTERNAL; 5467 } 5468 pm_phy = &pmc->phy[0]->pm_phy; 5469 5470 if (pm_phy == NULL) { 5471 return SOC_E_INTERNAL; 5472 } 5473 5474 /* Make a copy of the phy access and overwrite the desired lane */ 5475 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5476 5477 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5478 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5479 5480 SOC_IF_ERROR_RETURN(phymod_phy_cl72_status_get(&pm_phy_copy, &status)); 5481 *value = status.locked; 5482 5483 return(SOC_E_NONE); 5484 } 5485 5486 /* 5487 * phy8806x_prbs_rx_status_get 5488 */ 5489 STATIC int 5490 phy8806x_prbs_rx_status_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5491 { 5492 phymod_phy_access_t *pm_phy; 5493 phymod_prbs_status_t prbs_tmp; 5494 5495 /* just take the value from the first phy */ 5496 if (pmc->phy[0] == NULL) { 5497 return SOC_E_INTERNAL; 5498 } 5499 pm_phy = &pmc->phy[0]->pm_phy; 5500 5501 if (pm_phy == NULL) { 5502 return SOC_E_INTERNAL; 5503 } 5504 /* $$$ Need to add diagnostic API */ 5505 SOC_IF_ERROR_RETURN 5506 (phymod_phy_prbs_status_get(pm_phy, 0, &prbs_tmp)); 5507 if (prbs_tmp.prbs_lock == 0) { 5508 *value = -1; 5509 } else if ((prbs_tmp.prbs_lock_loss == 1) && (prbs_tmp.prbs_lock == 1)) { 5510 *value = -2; 5511 } else { 5512 *value = prbs_tmp.error_count; 5513 } 5514 5515 return(SOC_E_NONE); 5516 } 5517 5518 /* 5519 * phy8806x_loopback_internal_get 5520 */ 5521 STATIC int 5522 phy8806x_loopback_internal_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value) 5523 { 5524 phymod_phy_access_t *pm_phy; 5525 uint32_t enable; 5526 5527 /* just take the value from the first phy */ 5528 if (pmc->phy[0] == NULL) { 5529 return SOC_E_INTERNAL; 5530 } 5531 pm_phy = &pmc->phy[0]->pm_phy; 5532 5533 if (pm_phy == NULL) { 5534 return SOC_E_INTERNAL; 5535 } 5536 5537 if (sys) { 5538 SOC_IF_ERROR_RETURN 5539 (phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobal, &enable)); 5540 } else { 5541 SOC_IF_ERROR_RETURN 5542 (phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobal, &enable)); 5543 5544 } 5545 5546 *value = enable; 5547 5548 return(SOC_E_NONE); 5549 } 5550 5551 5552 /* 5553 * phy8806x_loopback_pmd_get (this is the PMD global loopback) 5554 */ 5555 STATIC int 5556 phy8806x_loopback_pmd_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value) 5557 { 5558 phymod_phy_access_t *pm_phy; 5559 uint32_t enable; 5560 5561 /* just take the value from the first phy */ 5562 if (pmc->phy[0] == NULL) { 5563 return SOC_E_INTERNAL; 5564 } 5565 pm_phy = &pmc->phy[0]->pm_phy; 5566 5567 if (pm_phy == NULL) { 5568 return SOC_E_INTERNAL; 5569 } 5570 5571 if (sys) { 5572 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobalPMD, &enable)); 5573 } else { 5574 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobalPMD, &enable)); 5575 } 5576 *value = enable; 5577 return(SOC_E_NONE); 5578 } 5579 5580 5581 /* 5582 * phy8806x_loopback_remote_get 5583 */ 5584 STATIC int 5585 phy8806x_loopback_remote_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value) 5586 { 5587 phymod_phy_access_t *pm_phy; 5588 uint32_t enable; 5589 5590 /* just take the value from the first phy */ 5591 if (pmc->phy[0] == NULL) { 5592 return SOC_E_INTERNAL; 5593 } 5594 pm_phy = &pmc->phy[0]->pm_phy; 5595 5596 if (pm_phy == NULL) { 5597 return SOC_E_INTERNAL; 5598 } 5599 5600 if (sys) { 5601 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysRemotePMD, &enable)); 5602 } else { 5603 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackRemotePMD, &enable)); 5604 } 5605 5606 *value = enable; 5607 return(SOC_E_NONE); 5608 } 5609 5610 /* 5611 * phy8806x_loopback_pcs_get 5612 */ 5613 /* STATIC */ int 5614 phy8806x_loopback_pcs_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value) 5615 { 5616 phymod_phy_access_t *pm_phy; 5617 uint32_t enable; 5618 5619 /* just take the value from the first phy */ 5620 if (pmc->phy[0] == NULL) { 5621 return SOC_E_INTERNAL; 5622 } 5623 pm_phy = &pmc->phy[0]->pm_phy; 5624 5625 if (pm_phy == NULL) { 5626 return SOC_E_INTERNAL; 5627 } 5628 5629 if (sys) { 5630 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysGlobalPCS, &enable)); 5631 } else { 5632 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackGlobalPCS, &enable)); 5633 } 5634 *value = enable; 5635 return(SOC_E_NONE); 5636 } 5637 5638 /* 5639 * phy8806x_loopback_remote_pcs_get 5640 */ 5641 STATIC int 5642 phy8806x_loopback_remote_pcs_get(soc_phymod_ctrl_t *pmc, int sys, uint32 *value) 5643 { 5644 phymod_phy_access_t *pm_phy; 5645 uint32_t enable; 5646 5647 /* just take the value from the first phy */ 5648 if (pmc->phy[0] == NULL) { 5649 return SOC_E_INTERNAL; 5650 } 5651 pm_phy = &pmc->phy[0]->pm_phy; 5652 5653 if (pm_phy == NULL) { 5654 return SOC_E_INTERNAL; 5655 } 5656 5657 if (sys) { 5658 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackSysRemotePCS, &enable)); 5659 } else { 5660 SOC_IF_ERROR_RETURN(phymod_phy_loopback_get(pm_phy, phymodLoopbackRemotePCS, &enable)); 5661 } 5662 *value = enable; 5663 return(SOC_E_NONE); 5664 } 5665 5666 /* 5667 * phy8806x_fec_get 5668 */ 5669 STATIC int 5670 phy8806x_fec_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5671 { 5672 phymod_phy_access_t *pm_phy; 5673 uint32_t enable; 5674 5675 /* just take the value from the first phy */ 5676 if (pmc->phy[0] == NULL) { 5677 return SOC_E_INTERNAL; 5678 } 5679 pm_phy = &pmc->phy[0]->pm_phy; 5680 5681 if (pm_phy == NULL) { 5682 return SOC_E_INTERNAL; 5683 } 5684 5685 SOC_IF_ERROR_RETURN(phymod_phy_fec_enable_get(pm_phy, &enable)); 5686 *value = enable; 5687 5688 return(SOC_E_NONE); 5689 } 5690 5691 5692 /* 5693 * phy8806x_tx_fir_pre_get 5694 */ 5695 STATIC int 5696 phy8806x_tx_fir_pre_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5697 { 5698 phymod_phy_access_t *pm_phy, pm_phy_copy; 5699 phymod_tx_t phymod_tx; 5700 soc_phymod_core_t *soc_core; 5701 5702 pm_phy = &pmc->phy[0]->pm_phy; 5703 5704 if (pm_phy == NULL) { 5705 return SOC_E_INTERNAL; 5706 } 5707 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5708 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5709 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5710 5711 5712 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5713 *value = phymod_tx.pre; 5714 5715 return(SOC_E_NONE); 5716 } 5717 5718 /* 5719 * phy8806x_tx_fir_main_get 5720 */ 5721 STATIC int 5722 phy8806x_tx_fir_main_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5723 { 5724 phymod_phy_access_t *pm_phy, pm_phy_copy; 5725 phymod_tx_t phymod_tx; 5726 soc_phymod_core_t *soc_core; 5727 5728 pm_phy = &pmc->phy[0]->pm_phy; 5729 5730 if (pm_phy == NULL) { 5731 return SOC_E_INTERNAL; 5732 } 5733 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5734 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5735 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5736 5737 5738 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5739 *value = phymod_tx.main; 5740 5741 return(SOC_E_NONE); 5742 } 5743 5744 /* 5745 * phy8806x_tx_fir_post_get 5746 */ 5747 STATIC int 5748 phy8806x_tx_fir_post_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5749 { 5750 phymod_phy_access_t *pm_phy, pm_phy_copy; 5751 phymod_tx_t phymod_tx; 5752 soc_phymod_core_t *soc_core; 5753 5754 pm_phy = &pmc->phy[0]->pm_phy; 5755 5756 if (pm_phy == NULL) { 5757 return SOC_E_INTERNAL; 5758 } 5759 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5760 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5761 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5762 5763 5764 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5765 *value = phymod_tx.post; 5766 5767 return(SOC_E_NONE); 5768 } 5769 5770 /* 5771 * phy8806x_tx_fir_post2_get 5772 */ 5773 STATIC int 5774 phy8806x_tx_fir_post2_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5775 { 5776 phymod_phy_access_t *pm_phy, pm_phy_copy; 5777 phymod_tx_t phymod_tx; 5778 soc_phymod_core_t *soc_core; 5779 5780 pm_phy = &pmc->phy[0]->pm_phy; 5781 5782 if (pm_phy == NULL) { 5783 return SOC_E_INTERNAL; 5784 } 5785 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5786 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5787 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5788 5789 5790 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5791 *value = phymod_tx.post2; 5792 5793 return(SOC_E_NONE); 5794 } 5795 5796 /* 5797 * phy8806x_tx_fir_post3_get 5798 */ 5799 STATIC int 5800 phy8806x_tx_fir_post3_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5801 { 5802 phymod_phy_access_t *pm_phy, pm_phy_copy; 5803 phymod_tx_t phymod_tx; 5804 soc_phymod_core_t *soc_core; 5805 5806 pm_phy = &pmc->phy[0]->pm_phy; 5807 5808 if (pm_phy == NULL) { 5809 return SOC_E_INTERNAL; 5810 } 5811 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5812 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5813 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5814 5815 5816 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5817 *value = phymod_tx.post3; 5818 5819 return(SOC_E_NONE); 5820 } 5821 5822 5823 /* 5824 * phy8806x_per_lane_preemphasis_get 5825 */ 5826 STATIC int 5827 phy8806x_per_lane_preemphasis_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value) 5828 { 5829 soc_phymod_phy_t *p_phy; 5830 uint32 lane_map; 5831 phymod_phy_access_t pm_phy_copy, *pm_phy; 5832 phymod_tx_t phymod_tx; 5833 soc_phymod_core_t *soc_core; 5834 5835 /* locate the desired phy and lane */ 5836 SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 5837 5838 /* Make a copy of the phy access and overwrite the desired lane */ 5839 pm_phy = &p_phy->pm_phy; 5840 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5841 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5842 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5843 pm_phy_copy.access.lane_mask = lane_map; 5844 5845 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5846 *value = phymod_tx.pre | (phymod_tx.main << 8) | (phymod_tx.post << 16); 5847 5848 return(SOC_E_NONE); 5849 } 5850 5851 5852 /* 5853 * phy8806x_preemphasis_get 5854 */ 5855 STATIC int 5856 phy8806x_preemphasis_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5857 { 5858 phymod_phy_access_t *pm_phy, pm_phy_copy; 5859 phymod_tx_t phymod_tx; 5860 soc_phymod_core_t *soc_core; 5861 5862 pm_phy = &pmc->phy[0]->pm_phy; 5863 5864 if (pm_phy == NULL) { 5865 return SOC_E_INTERNAL; 5866 } 5867 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5868 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5869 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5870 5871 5872 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5873 *value = phymod_tx.pre | (phymod_tx.main << 8) | (phymod_tx.post << 16); 5874 5875 return(SOC_E_NONE); 5876 } 5877 5878 5879 /* 5880 * phy8806x_per_lane_driver_current_get 5881 */ 5882 STATIC int 5883 phy8806x_per_lane_driver_current_get(soc_phymod_ctrl_t *pmc, int lane, uint32 *value) 5884 { 5885 soc_phymod_phy_t *p_phy; 5886 uint32 lane_map; 5887 phymod_phy_access_t pm_phy_copy, *pm_phy; 5888 phymod_tx_t phymod_tx; 5889 soc_phymod_core_t *soc_core; 5890 5891 /* locate the desired phy and lane */ 5892 SOC_IF_ERROR_RETURN(_phy8806x_find_soc_phy_lane(pmc, lane, &p_phy, &lane_map)); 5893 5894 /* Make a copy of the phy access and overwrite the desired lane */ 5895 pm_phy = &p_phy->pm_phy; 5896 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5897 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5898 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5899 pm_phy_copy.access.lane_mask = lane_map; 5900 5901 SOC_IF_ERROR_RETURN(phymod_phy_tx_get(&pm_phy_copy, &phymod_tx)); 5902 *value = phymod_tx.amp; 5903 5904 return(SOC_E_NONE); 5905 } 5906 5907 STATIC int 5908 phy8806x_firmware_dfe_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5909 { 5910 phymod_phy_access_t pm_phy_copy, *pm_phy; 5911 phymod_firmware_lane_config_t fw_config; 5912 soc_phymod_core_t *soc_core; 5913 5914 /* just take the value from the first phy */ 5915 if (pmc->phy[0] == NULL) { 5916 return SOC_E_INTERNAL; 5917 } 5918 5919 pm_phy = &pmc->phy[0]->pm_phy; 5920 if (pm_phy == NULL) { 5921 return SOC_E_INTERNAL; 5922 } 5923 5924 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5925 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5926 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5927 5928 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 5929 5930 if (fw_config.DfeOn) { 5931 *value = 1; 5932 } else { 5933 *value = 0; 5934 } 5935 5936 return(SOC_E_NONE); 5937 } 5938 5939 STATIC int 5940 phy8806x_firmware_unreliable_los_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5941 { 5942 phymod_phy_access_t pm_phy_copy, *pm_phy; 5943 phymod_firmware_lane_config_t fw_config; 5944 soc_phymod_core_t *soc_core; 5945 5946 /* just take the value from the first phy */ 5947 if (pmc->phy[0] == NULL) { 5948 return SOC_E_INTERNAL; 5949 } 5950 5951 pm_phy = &pmc->phy[0]->pm_phy; 5952 if (pm_phy == NULL) { 5953 return SOC_E_INTERNAL; 5954 } 5955 5956 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5957 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5958 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5959 5960 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 5961 5962 if (fw_config.UnreliableLos) { 5963 *value = 1; 5964 } else { 5965 *value = 0; 5966 } 5967 5968 return(SOC_E_NONE); 5969 } 5970 5971 STATIC int 5972 phy8806x_firmware_lp_dfe_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value) 5973 { 5974 phymod_phy_access_t pm_phy_copy, *pm_phy; 5975 phymod_firmware_lane_config_t fw_config; 5976 soc_phymod_core_t *soc_core; 5977 5978 /* just take the value from the first phy */ 5979 if (pmc->phy[0] == NULL) { 5980 return SOC_E_INTERNAL; 5981 } 5982 5983 pm_phy = &pmc->phy[0]->pm_phy; 5984 if (pm_phy == NULL) { 5985 return SOC_E_INTERNAL; 5986 } 5987 5988 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 5989 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 5990 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 5991 5992 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 5993 5994 if (fw_config.LpDfeOn) { 5995 *value = 1; 5996 } else { 5997 *value = 0; 5998 } 5999 6000 return(SOC_E_NONE); 6001 } 6002 6003 /* 6004 * tscf_firmware_dfe_enable_get 6005 */ 6006 STATIC int 6007 phy8806x_firmware_br_dfe_enable_get(soc_phymod_ctrl_t *pmc, uint32 *value) 6008 { 6009 phymod_phy_access_t pm_phy_copy, *pm_phy; 6010 phymod_firmware_lane_config_t fw_config; 6011 soc_phymod_core_t *soc_core; 6012 6013 /* just take the value from the first phy */ 6014 if (pmc->phy[0] == NULL) { 6015 return SOC_E_INTERNAL; 6016 } 6017 6018 pm_phy = &pmc->phy[0]->pm_phy; 6019 if (pm_phy == NULL) { 6020 return SOC_E_INTERNAL; 6021 } 6022 6023 sal_memcpy(&pm_phy_copy, pm_phy, sizeof(pm_phy_copy)); 6024 soc_core = PHYMOD_ACC_USER_ACC(&pm_phy_copy.access); 6025 pm_phy_copy.port_loc = (EXT_PHY_SW_STATE(soc_core->unit, soc_core->port)->flags & PHYCTRL_SYS_SIDE_CTRL) ? phymodPortLocSys : phymodPortLocLine; 6026 6027 SOC_IF_ERROR_RETURN(phymod_phy_firmware_lane_config_get(&pm_phy_copy, &fw_config)); 6028 6029 if (fw_config.ForceBrDfe) { 6030 *value = 1; 6031 } else { 6032 *value = 0; 6033 } 6034 6035 return(SOC_E_NONE); 6036 } 6037 6038 6039 /* 6040 * Function: 6041 * phy_8806x_control_get 6042 * Purpose: 6043 * Get current control settings of the PHY. 6044 * Parameters: 6045 * unit - BCM unit number. 6046 * port - Port number. 6047 * type - Control to update 6048 * value - (OUT) Current setting for the control 6049 * Returns: 6050 * SOC_E_NONE 6051 */ 6052 STATIC int 6053 phy_8806x_control_get(int unit, soc_port_t port, soc_phy_control_t type, uint32 *value) 6054 { 6055 int rv; 6056 phy_ctrl_t *pc; 6057 soc_phymod_ctrl_t *pmc; 6058 /* phy8806x_config_t *pCfg; */ 6059 6060 if ((type < 0) || (type >= SOC_PHY_CONTROL_COUNT)) { 6061 return (SOC_E_PARAM); 6062 } 6063 6064 /* locate phy control */ 6065 pc = EXT_PHY_SW_STATE(unit, port); 6066 if (pc == NULL) { 6067 return SOC_E_INTERNAL; 6068 } 6069 6070 #if defined(INCLUDE_FCMAP) 6071 /* Skip all loopback get for FC */ 6072 if ((pc->fcmap_enable) && 6073 (type == SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS)) { 6074 return SOC_E_NONE; 6075 } 6076 #endif 6077 6078 pmc = &pc->phymod_ctrl; 6079 /* pCfg = (phy8806x_config_t *) pc->driver_data; */ 6080 6081 switch(type) { 6082 case SOC_PHY_CONTROL_UNRELIABLE_LOS: 6083 rv = phy8806x_firmware_unreliable_los_get(pmc, value); 6084 break; 6085 case SOC_PHY_CONTROL_FIRMWARE_DFE_ENABLE: 6086 rv = phy8806x_firmware_dfe_enable_get(pmc, value); 6087 break; 6088 case SOC_PHY_CONTROL_FIRMWARE_LP_DFE_ENABLE: 6089 rv = phy8806x_firmware_lp_dfe_enable_get(pmc, value); 6090 break; 6091 case SOC_PHY_CONTROL_FIRMWARE_BR_DFE_ENABLE: 6092 rv = phy8806x_firmware_br_dfe_enable_get(pmc, value); 6093 break; 6094 /* CL72 */ 6095 case SOC_PHY_CONTROL_CL72: 6096 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 6097 *value = *value | PORT_SYS_SIDE_CTRL; 6098 } 6099 rv = phy8806x_cl72_enable_get(pmc, value); 6100 break; 6101 case SOC_PHY_CONTROL_CL72_STATUS: 6102 rv = phy8806x_cl72_status_get(pmc, value); 6103 break; 6104 6105 case SOC_PHY_CONTROL_PRBS_RX_STATUS: 6106 rv = phy8806x_prbs_rx_status_get(pmc, value); 6107 break; 6108 6109 /* LOOPBACK */ 6110 case SOC_PHY_CONTROL_LOOPBACK_INTERNAL: 6111 rv = phy8806x_loopback_internal_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 6112 break; 6113 case SOC_PHY_CONTROL_LOOPBACK_REMOTE: 6114 rv = phy8806x_loopback_remote_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 6115 break; 6116 case SOC_PHY_CONTROL_LOOPBACK_REMOTE_PCS_BYPASS: 6117 rv = phy8806x_loopback_remote_pcs_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 6118 break; 6119 case SOC_PHY_CONTROL_LOOPBACK_PMD: 6120 rv = phy8806x_loopback_pmd_get(pmc, pc->flags & PHYCTRL_SYS_SIDE_CTRL, value); 6121 break; 6122 6123 /* FEC */ 6124 case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION: 6125 *value = 0; 6126 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 6127 LOG_CLI((BSL_META_U(unit, "PHYCTRL_SYS_SIDE_CTRL \n"))); 6128 *value = *value | PORT_SYS_SIDE_CTRL; 6129 } 6130 rv = phy8806x_fec_enable_get(pmc, value); 6131 if (*value != 1) /* Clear if the FEC is not CL74 (value 1) */ 6132 *value = 0; 6133 break; 6134 6135 case SOC_PHY_CONTROL_FORWARD_ERROR_CORRECTION_CL91: 6136 *value = 0; 6137 if (pc->flags & PHYCTRL_SYS_SIDE_CTRL) { 6138 LOG_CLI((BSL_META_U(unit, "PHYCTRL_SYS_SIDE_CTRL \n"))); 6139 *value = *value | PORT_SYS_SIDE_CTRL; 6140 } 6141 rv = phy8806x_fec_enable_get(pmc, value); 6142 6143 if (*value == 2) /* Set only if the FEC is CL91 (value 2) */ 6144 *value = 1; 6145 else 6146 *value = 0; /* Clear if the FEC is not set to CL91 (value 2) */ 6147 6148 break; 6149 6150 case SOC_PHY_CONTROL_FORCED_SPEED_LINE_SIDE: 6151 rv = phy8806x_forced_speed_line_side_get(pmc, value); 6152 break; 6153 case SOC_PHY_CONTROL_AUTONEG_LINE_SIDE: 6154 rv = phy8806x_autoneg_line_side_get(pmc, value); 6155 break; 6156 case SOC_PHY_CONTROL_EGRESS_FLOW_CONTROL_MODE: 6157 rv = phy8806x_flow_control_mode_get(pmc, 0, value); 6158 break; 6159 case SOC_PHY_CONTROL_INGRESS_FLOW_CONTROL_MODE: 6160 rv = phy8806x_flow_control_mode_get(pmc, 1, value); 6161 break; 6162 case SOC_PHY_CONTROL_PSM_COS_BMP: 6163 rv = phy8806x_psm_cos_bmp_get(pmc, value); 6164 break; 6165 case SOC_PHY_CONTROL_PFC_USE_IP_COS: 6166 rv = phy8806x_pfc_use_ip_cos_get(pmc, value); 6167 break; 6168 /* PREEMPHASIS */ 6169 case SOC_PHY_CONTROL_PREEMPHASIS_LANE0: 6170 rv = phy8806x_per_lane_preemphasis_get(pmc, 0, value); 6171 break; 6172 case SOC_PHY_CONTROL_PREEMPHASIS_LANE1: 6173 rv = phy8806x_per_lane_preemphasis_get(pmc, 1, value); 6174 break; 6175 case SOC_PHY_CONTROL_PREEMPHASIS_LANE2: 6176 rv = phy8806x_per_lane_preemphasis_get(pmc, 2, value); 6177 break; 6178 case SOC_PHY_CONTROL_PREEMPHASIS_LANE3: 6179 rv = phy8806x_per_lane_preemphasis_get(pmc, 3, value); 6180 break; 6181 case SOC_PHY_CONTROL_PREEMPHASIS: 6182 rv = phy8806x_preemphasis_get(pmc, value); 6183 break; 6184 case SOC_PHY_CONTROL_TX_FIR_PRE: 6185 /* assume they are all the same as lane 0 */ 6186 rv = phy8806x_tx_fir_pre_get(pmc, value); 6187 break; 6188 case SOC_PHY_CONTROL_TX_FIR_MAIN: 6189 /* assume they are all the same as lane 0 */ 6190 rv = phy8806x_tx_fir_main_get(pmc, value); 6191 break; 6192 case SOC_PHY_CONTROL_TX_FIR_POST: 6193 /* assume they are all the same as lane 0 */ 6194 rv = phy8806x_tx_fir_post_get(pmc, value); 6195 break; 6196 case SOC_PHY_CONTROL_TX_FIR_POST2: 6197 /* assume they are all the same as lane 0 */ 6198 rv = phy8806x_tx_fir_post2_get(pmc, value); 6199 break; 6200 case SOC_PHY_CONTROL_TX_FIR_POST3: 6201 /* assume they are all the same as lane 0 */ 6202 rv = phy8806x_tx_fir_post3_get(pmc, value); 6203 break; 6204 6205 /* DRIVER CURRENT */ 6206 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE0: 6207 rv = phy8806x_per_lane_driver_current_get(pmc, 0, value); 6208 break; 6209 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE1: 6210 rv = phy8806x_per_lane_driver_current_get(pmc, 1, value); 6211 break; 6212 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE2: 6213 rv = phy8806x_per_lane_driver_current_get(pmc, 2, value); 6214 break; 6215 case SOC_PHY_CONTROL_DRIVER_CURRENT_LANE3: 6216 rv = phy8806x_per_lane_driver_current_get(pmc, 3, value); 6217 break; 6218 case SOC_PHY_CONTROL_DRIVER_CURRENT: 6219 rv = phy8806x_per_lane_driver_current_get(pmc, 0, value); 6220 break; 6221 case SOC_PHY_CONTROL_SOFTWARE_RX_LOS: 6222 case SOC_PHY_CONTROL_EEE: 6223 case SOC_PHY_CONTROL_EEE_AUTO: 6224 *value = FALSE; 6225 rv = SOC_E_NONE; 6226 break; 6227 case SOC_PHY_CONTROL_INTERFACE: 6228 rv = phy_8806x_interface_get(unit, port, (soc_port_if_t *)value); 6229 break; 6230 /* UNAVAIL */ 6231 default: 6232 rv = SOC_E_UNAVAIL; 6233 break; 6234 } 6235 return rv; 6236 } 6237 6238 /* 6239 * Function: 6240 * phy_8806x_reg_read 6241 * Purpose: 6242 * Routine to read PHY register 6243 * Parameters: 6244 * unit - BCM unit number 6245 * port - Port number 6246 * flags - Flags which specify the register type 6247 * phy_reg_addr - Encoded register address 6248 * phy_data - (OUT) Value read from PHY register 6249 * Note: 6250 * This register read function is not thread safe. Higher level 6251 * function that calls this function must obtain a per port lock 6252 * to avoid overriding register page mapping between threads. 6253 */ 6254 STATIC int 6255 phy_8806x_reg_read(int unit, soc_port_t port, uint32 flags, 6256 uint32 phy_reg_addr, uint32 *phy_reg_data) 6257 { 6258 phy_ctrl_t *pc; 6259 soc_phymod_ctrl_t *pmc; 6260 phymod_phy_access_t *pm_phy; 6261 int idx=0; 6262 uint32 data = 0; 6263 6264 pc = EXT_PHY_SW_STATE(unit, port); 6265 if (pc == NULL) { 6266 return SOC_E_INTERNAL; 6267 } 6268 6269 pmc = &pc->phymod_ctrl; 6270 pm_phy = &pmc->phy[idx]->pm_phy; 6271 if (flags & SOC_PHY_I2C_DATA8) { 6272 SOC_IF_ERROR_RETURN 6273 (phymod_phy_i2c_read(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 1, (uint8 *)&data)); 6274 data = LE2HOST32(data); 6275 *phy_reg_data = data & 0xff; 6276 } else if (flags & SOC_PHY_I2C_DATA16) { 6277 SOC_IF_ERROR_RETURN 6278 (phymod_phy_i2c_read(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 2, (uint8 *)&data)); 6279 data = LE2HOST32(data); 6280 *phy_reg_data = data & 0xffff; 6281 } else if (flags & SOC_PHY_PVT_DATA) { 6282 SOC_IF_ERROR_RETURN 6283 (phymod_phy_private_read(pm_phy, phy_reg_addr, phy_reg_data)); 6284 } else { 6285 SOC_IF_ERROR_RETURN 6286 (phymod_phy_reg_read(pm_phy, phy_reg_addr, phy_reg_data)); 6287 } 6288 6289 return SOC_E_NONE; 6290 } 6291 6292 /* 6293 * Function: 6294 * phy_8806x_reg_write 6295 * Purpose: 6296 * Routine to write PHY register 6297 * Parameters: 6298 * uint - BCM unit number 6299 * pc - PHY state 6300 * flags - Flags which specify the register type 6301 * phy_reg_addr - Encoded register address 6302 * phy_data - Value write to PHY register 6303 * Note: 6304 * This register read function is not thread safe. Higher level 6305 * function that calls this function must obtain a per port lock 6306 * to avoid overriding register page mapping between threads. 6307 */ 6308 STATIC int 6309 phy_8806x_reg_write(int unit, soc_port_t port, uint32 flags, 6310 uint32 phy_reg_addr, uint32 phy_reg_data) 6311 { 6312 phy_ctrl_t *pc; 6313 soc_phymod_ctrl_t *pmc; 6314 phymod_phy_access_t *pm_phy; 6315 int idx; 6316 uint32 data = 0; 6317 6318 pc = EXT_PHY_SW_STATE(unit, port); 6319 if (pc == NULL) { 6320 return SOC_E_INTERNAL; 6321 } 6322 6323 pmc = &pc->phymod_ctrl; 6324 for (idx = 0; idx < pmc->num_phys; idx++) { 6325 pm_phy = &pmc->phy[idx]->pm_phy; 6326 if (flags & SOC_PHY_I2C_DATA8) { 6327 data = phy_reg_data & 0xFF; 6328 SOC_IF_ERROR_RETURN 6329 (phymod_phy_i2c_write(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 1, (uint8 *)&data)); 6330 } else if (flags & SOC_PHY_I2C_DATA16) { 6331 data = phy_reg_data & 0xFFFF; 6332 SOC_IF_ERROR_RETURN 6333 (phymod_phy_i2c_write(pm_phy, 0, SOC_PHY_I2C_DEVAD(phy_reg_addr), SOC_PHY_I2C_REGAD(phy_reg_addr), 2, (uint8 *)&data)); 6334 } else if (flags & SOC_PHY_PVT_DATA) { 6335 SOC_IF_ERROR_RETURN 6336 (phymod_phy_private_write(pm_phy, phy_reg_addr, phy_reg_data)); 6337 } else { 6338 SOC_IF_ERROR_RETURN 6339 (phymod_phy_reg_write(pm_phy, phy_reg_addr, phy_reg_data)); 6340 } 6341 } 6342 return SOC_E_NONE; 6343 } 6344 6345 /* 6346 * Function: 6347 * phy_8806x_reg_modify 6348 * Purpose: 6349 * Routine to write PHY register 6350 * Parameters: 6351 * uint - BCM unit number 6352 * pc - PHY state 6353 * flags - Flags which specify the register type 6354 * phy_reg_addr - Encoded register address 6355 * phy_mo_data - New value for the bits specified in phy_mo_mask 6356 * phy_mo_mask - Bit mask to modify 6357 * Note: 6358 * This function is not thread safe. Higher level 6359 * function that calls this function must obtain a per port lock 6360 * to avoid overriding register page mapping between threads. 6361 */ 6362 STATIC int 6363 phy_8806x_reg_modify(int unit, soc_port_t port, uint32 flags, 6364 uint32 phy_reg_addr, uint32 phy_data, 6365 uint32 phy_data_mask) 6366 { 6367 phy_ctrl_t *pc; 6368 soc_phymod_ctrl_t *pmc; 6369 phymod_phy_access_t *pm_phy; 6370 uint32 data32, tmp; 6371 int idx; 6372 6373 pc = EXT_PHY_SW_STATE(unit, port); 6374 if (pc == NULL) { 6375 return SOC_E_INTERNAL; 6376 } 6377 6378 pmc = &pc->phymod_ctrl; 6379 for (idx = 0; idx < pmc->num_phys; idx++) { 6380 pm_phy = &pmc->phy[idx]->pm_phy; 6381 SOC_IF_ERROR_RETURN 6382 (phymod_phy_reg_read(pm_phy, phy_reg_addr, &data32)); 6383 tmp = data32; 6384 data32 &= ~(phy_data_mask); 6385 data32 |= (phy_data & phy_data_mask); 6386 if (data32 != tmp) { 6387 SOC_IF_ERROR_RETURN 6388 (phymod_phy_reg_write(pm_phy, phy_reg_addr, data32)); 6389 } 6390 } 6391 return SOC_E_NONE; 6392 } 6393 6394 /* 6395 * Function: 6396 * phy_8806x_multi_reg_read 6397 * Purpose: 6398 * Routine to read PHY I2C data 6399 * Parameters: 6400 * unit - BCM unit number 6401 * port - Port number 6402 * flags - Flags which specify the register type 6403 * dev_addr - device address 6404 * offset - IC map offset 6405 * maxsize - size of buffer provided to read 6406 * data - (OUT) Value read from PHY register 6407 * actual_size - (OUT) actual amount of data read 6408 * Note: 6409 * This register read function is not thread safe. Higher level 6410 * function that calls this function must obtain a per port lock 6411 * to avoid overriding register page mapping between threads. 6412 */ 6413 STATIC int 6414 phy_8806x_multi_reg_read(int unit, soc_port_t port, uint32 flags, 6415 uint32 dev_addr, uint32 offset, int max_size, uint8 *data, int *actual_size) 6416 { 6417 phy_ctrl_t *pc; 6418 soc_phymod_ctrl_t *pmc; 6419 phymod_phy_access_t *pm_phy; 6420 int idx=0; 6421 6422 pc = EXT_PHY_SW_STATE(unit, port); 6423 if (pc == NULL) { 6424 return SOC_E_INTERNAL; 6425 } 6426 6427 pmc = &pc->phymod_ctrl; 6428 pm_phy = &pmc->phy[idx]->pm_phy; 6429 6430 /* Endian unaware byte stream Returned */ 6431 *actual_size = 0; 6432 SOC_IF_ERROR_RETURN 6433 (phymod_phy_i2c_read(pm_phy, 0, dev_addr, offset, max_size, (uint8 *)data)); 6434 *actual_size = max_size; 6435 return SOC_E_NONE; 6436 } 6437 6438 STATIC void 6439 phy_8806x_cleanup(soc_phymod_ctrl_t *pmc) 6440 { 6441 int idx; 6442 soc_phymod_phy_t *phy; 6443 soc_phymod_core_t *core; 6444 6445 for (idx = 0; idx < pmc->num_phys ; idx++) { 6446 phy = pmc->phy[idx]; 6447 if (phy == NULL) { 6448 LOG_WARN(BSL_LS_SOC_PHY, 6449 (BSL_META_U(pmc->unit, 6450 "phy object is empty"))); 6451 continue; 6452 } 6453 6454 core = phy->core; 6455 6456 /* Destroy core object if not used anymore */ 6457 if (core && core->ref_cnt) { 6458 if (--core->ref_cnt == 0) { 6459 soc_phymod_core_destroy(pmc->unit, core); 6460 } 6461 } 6462 6463 /* Destroy phy object */ 6464 if (phy) { 6465 soc_phymod_phy_destroy(pmc->unit, phy); 6466 } 6467 } 6468 pmc->num_phys = 0; 6469 } 6470 6471 STATIC void 6472 phy_8806x_core_init(phy_ctrl_t *pc, soc_phymod_core_t *core, 6473 phymod_bus_t *core_bus, uint32 core_addr) 6474 { 6475 phymod_core_access_t *pm_core; 6476 phymod_access_t *pm_acc; 6477 6478 core->unit = pc->unit; 6479 core->port = pc->port; 6480 core->read = pc->read; 6481 core->write = pc->write; 6482 core->wrmask = pc->wrmask; 6483 6484 pm_core = &core->pm_core; 6485 phymod_core_access_t_init(pm_core); 6486 pm_acc = &pm_core->access; 6487 phymod_access_t_init(pm_acc); 6488 PHYMOD_ACC_USER_ACC(pm_acc) = core; 6489 PHYMOD_ACC_BUS(pm_acc) = core_bus; 6490 PHYMOD_ACC_ADDR(pm_acc) = core_addr; 6491 PHYMOD_ACC_EXT_ACC(pm_acc) = _8806x_xmod_command; 6492 6493 if (soc_property_port_get(pc->unit, pc->port, "phy8806x_sim", 0) == 45) { 6494 PHYMOD_ACC_F_CLAUSE45_SET(pm_acc); 6495 } 6496 6497 return; 6498 } 6499 6500 /* 6501 * Function: 6502 * phy_8806x_probe 6503 * Purpose: 6504 * xx 6505 * Parameters: 6506 * pc->phy_id (IN) 6507 * pc->unit (IN) 6508 * pc->port (IN) 6509 * pc->size (OUT) - memory required by phy port 6510 * pc->dev_name (OUT) - set to port device name 6511 * 6512 * Note: 6513 */ 6514 STATIC int 6515 phy_8806x_probe(int unit, phy_ctrl_t *pc) 6516 { 6517 int rv, idx; 6518 uint32 lane_map, num_phys, core_id, phy_id /*, found */; 6519 uint32 top_dev_rev_id; 6520 phymod_bus_t core_bus; 6521 phymod_dispatch_type_t phy_type; 6522 phymod_core_access_t *pm_core; 6523 phymod_phy_access_t *pm_phy; 6524 phymod_access_t *pm_acc; 6525 soc_phymod_ctrl_t *pmc; 6526 soc_phymod_phy_t *phy; 6527 soc_phymod_core_t *core; 6528 soc_phymod_core_t core_probe; 6529 soc_info_t *si; 6530 phyident_core_info_t core_info[8]; 6531 int array_max = 8; 6532 int array_size = 0; 6533 int port; 6534 int phy_port; /* physical port number */ 6535 6536 if (!(SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit))) { 6537 /* Release the top level resets before the AXI reads. */ 6538 SOC_IF_ERROR_RETURN 6539 (WRITE_TOP_SOFT_RESET_REG(unit, pc, 0xc000003f)); 6540 } 6541 6542 SOC_IF_ERROR_RETURN 6543 (READ_TOP_DEV_REV_ID_REG(unit, pc, &top_dev_rev_id)); 6544 6545 switch (top_dev_rev_id & 0xff) { 6546 case 0x60: 6547 pc->dev_name = "BCM88060"; 6548 break; 6549 6550 case 0x61: 6551 pc->dev_name = "BCM88061"; 6552 break; 6553 6554 case 0x64: 6555 pc->dev_name = "BCM88064"; 6556 break; 6557 6558 case 0x68: 6559 pc->dev_name = "BCM88068"; 6560 break; 6561 6562 default: 6563 break; 6564 } 6565 6566 /* Initialize PHY bus */ 6567 SOC_IF_ERROR_RETURN(phymod_bus_t_init(&core_bus)); 6568 core_bus.bus_name = "phy8806x"; 6569 core_bus.read = _8806x_reg_read; 6570 core_bus.write = _8806x_reg_write; 6571 6572 /* Configure PHY bus properties */ 6573 PHYMOD_BUS_CAP_WR_MODIFY_SET(&core_bus); 6574 PHYMOD_BUS_CAP_LANE_CTRL_SET(&core_bus); 6575 6576 port = pc->port; 6577 pmc = &pc->phymod_ctrl; 6578 si = &SOC_INFO(unit); 6579 if (soc_feature(unit, soc_feature_logical_port_num)) { 6580 phy_port = si->port_l2p_mapping[port]; 6581 } else { 6582 phy_port = port; 6583 } 6584 6585 /* Install clean up function */ 6586 pmc->unit = pc->unit; 6587 pmc->cleanup = phy_8806x_cleanup; 6588 #if 0 6589 pmc->symbols = NULL; /*&bcmi_8806x_xgxs_symbols;*/ 6590 #endif 6591 6592 6593 pc->lane_num = SOC_PORT_BINDEX(unit, phy_port); 6594 pc->chip_num = SOC_BLOCK_NUMBER(unit, SOC_PORT_BLOCK(unit, phy_port)); 6595 6596 /* request memory for the configuration structure */ 6597 pc->size = sizeof(phy8806x_config_t); 6598 6599 /* Bit N corresponds to lane N in lane_map */ 6600 lane_map = 0xf; 6601 num_phys = 1; 6602 switch (si->port_num_lanes[port]) { 6603 case 4: 6604 pc->phy_mode = PHYCTRL_QUAD_LANE_PORT; 6605 break; 6606 case 2: 6607 lane_map = 0x3; 6608 pc->phy_mode = PHYCTRL_DUAL_LANE_PORT; 6609 break; 6610 case 1: 6611 case 0: 6612 lane_map = 0x1; 6613 pc->phy_mode = PHYCTRL_ONE_LANE_PORT; 6614 break; 6615 default: 6616 return SOC_E_CONFIG; 6617 } 6618 lane_map <<= pc->lane_num; 6619 6620 /* we need to get the other core id if more than 1 core per port */ 6621 if (num_phys > 1) { 6622 /* get the other core address */ 6623 SOC_IF_ERROR_RETURN 6624 (soc_phy_addr_multi_get(unit, port, array_max, &array_size, &core_info[0])); 6625 } else { 6626 core_info[0].mdio_addr = pc->phy_id; 6627 } 6628 6629 phy_type = phymodDispatchTypePhy8806x; /* Change to XMOD SRINATH */ 6630 6631 /* Probe cores */ 6632 for (idx = 0; idx < num_phys ; idx++) { 6633 phy_8806x_core_init(pc, &core_probe, &core_bus, 6634 core_info[idx].mdio_addr); 6635 pm_core = &core_probe.pm_core; 6636 pm_core->type = phy_type; 6637 } 6638 6639 rv = SOC_E_NONE; 6640 for (idx = 0; idx < num_phys ; idx++) { 6641 /* Set core and phy IDs based on PHY address */ 6642 core_id = pc->phy_id + idx; 6643 phy_id = (lane_map << 16) | core_id; 6644 6645 /* Create PHY object */ 6646 rv = soc_phymod_phy_create(unit, phy_id, &pmc->phy[idx]); 6647 if (SOC_FAILURE(rv)) { 6648 break; 6649 } 6650 pmc->num_phys++; 6651 6652 /* Initialize phy object */ 6653 phy = pmc->phy[idx]; 6654 pm_phy = &phy->pm_phy; 6655 phymod_phy_access_t_init(pm_phy); 6656 6657 /* Find or create associated core object */ 6658 rv = soc_phymod_core_find_by_id(unit, core_id, &phy->core); 6659 if (rv == SOC_E_NOT_FOUND) { 6660 rv = soc_phymod_core_create(unit, core_id, &phy->core); 6661 } 6662 if (SOC_FAILURE(rv)) { 6663 break; 6664 } 6665 } 6666 if (SOC_FAILURE(rv)) { 6667 phy_8806x_cleanup(pmc); 6668 return rv; 6669 } 6670 6671 for (idx = 0; idx < pmc->num_phys ; idx++) { 6672 phy = pmc->phy[idx]; 6673 core = phy->core; 6674 pm_core = &core->pm_core; 6675 6676 /* Initialize core object if newly created */ 6677 if (core->ref_cnt == 0) { 6678 sal_memcpy(&core->pm_bus, &core_bus, sizeof(core->pm_bus)); 6679 phy_8806x_core_init(pc, core, &core->pm_bus, 6680 core_info[idx].mdio_addr); 6681 /* Set dispatch type */ 6682 pm_core->type = phy_type; 6683 } 6684 core->ref_cnt++; 6685 6686 /* Initialize phy access based on associated core */ 6687 pm_acc = &phy->pm_phy.access; 6688 sal_memcpy(pm_acc, &pm_core->access, sizeof(*pm_acc)); 6689 phy->pm_phy.type = phy_type; 6690 PHYMOD_ACC_LANE_MASK(pm_acc) = lane_map; 6691 } 6692 6693 return SOC_E_NONE; 6694 } 6695 6696 6697 /*********************************************************************** 6698 * 6699 * PASS-THROUGH NOTIFY ROUTINES 6700 */ 6701 6702 /* 6703 * Function: 6704 * _8806x_notify_duplex 6705 * Purpose: 6706 * Program duplex if (and only if) serdesphy8806x is an intermediate PHY. 6707 * Parameters: 6708 * unit - BCM unit number. 6709 * port - Port number. 6710 * duplex - Boolean, TRUE indicates full duplex, FALSE 6711 * indicates half. 6712 * Returns: 6713 * SOC_E_XXX 6714 * Notes: 6715 * If PHY_FLAGS_FIBER is set, it indicates the PHY is being used to 6716 * talk directly to an external fiber module. 6717 * 6718 * If PHY_FLAGS_FIBER is clear, the PHY is being used in 6719 * pass-through mode to talk to an external SGMII PHY. 6720 * 6721 * When used in pass-through mode, autoneg must be turned off and 6722 * the speed/duplex forced to match that of the external PHY. 6723 */ 6724 6725 6726 /* 6727 * Function: 6728 * _8806x_stop 6729 * Purpose: 6730 * Put serdesphy8806x SERDES in or out of reset depending on conditions 6731 */ 6732 6733 STATIC int 6734 _8806x_stop(int unit, soc_port_t port) 6735 { 6736 phy_ctrl_t* pc; 6737 soc_phymod_ctrl_t *pmc; 6738 phymod_phy_access_t *pm_phy; 6739 phymod_phy_power_t phy_power; 6740 int stop, copper, speed; 6741 6742 pc = EXT_PHY_SW_STATE(unit, port); 6743 pmc = &pc->phymod_ctrl; 6744 pm_phy = &pmc->phy[0]->pm_phy; 6745 6746 if (pc->phy_mode != PHYCTRL_ONE_LANE_PORT) { 6747 return SOC_E_NONE; 6748 } 6749 6750 /* 'Stop' only for speeds < 10G. */ 6751 SOC_IF_ERROR_RETURN 6752 (phy_8806x_speed_get(unit,port,&speed)); 6753 if(10000 <= speed) { 6754 return SOC_E_NONE; 6755 } 6756 copper = (pc->stop & 6757 PHY_STOP_COPPER) != 0; 6758 6759 stop = ((pc->stop & 6760 (PHY_STOP_PHY_DIS | 6761 PHY_STOP_DRAIN)) != 0 || 6762 (copper && 6763 (pc->stop & 6764 (PHY_STOP_MAC_DIS | 6765 PHY_STOP_DUPLEX_CHG | 6766 PHY_STOP_SPEED_CHG)) != 0)); 6767 6768 LOG_INFO(BSL_LS_SOC_PHY, 6769 (BSL_META_U(pc->unit, 6770 "qsgmiie_stop: u=%d p=%d copper=%d stop=%d flg=0x%x\n"), 6771 unit, port, copper, stop, 6772 pc->stop)); 6773 if (stop) { 6774 phy_power.tx = phymodPowerOff; 6775 phy_power.rx = phymodPowerOff; 6776 } else { 6777 phy_power.tx = phymodPowerOn; 6778 phy_power.rx = phymodPowerOn; 6779 } 6780 SOC_IF_ERROR_RETURN 6781 (phymod_phy_power_set(pm_phy, &phy_power)); 6782 return SOC_E_NONE; 6783 } 6784 6785 /* 6786 * Function: 6787 * _8806x_notify_stop 6788 * Purpose: 6789 * Add a reason to put serdesphy8806x PHY in reset. 6790 * Parameters: 6791 * unit - BCM unit number. 6792 * port - Port number. 6793 * flags - Reason to stop 6794 * Returns: 6795 * SOC_E_XXX 6796 */ 6797 6798 int 6799 _8806x_notify_stop(int unit, soc_port_t port, uint32 flags) 6800 { 6801 EXT_PHY_SW_STATE(unit, port)->stop |= flags; 6802 return _8806x_stop(unit, port); 6803 } 6804 6805 /* 6806 * Function: 6807 * _8806x_notify_resume 6808 * Purpose: 6809 * Remove a reason to put serdesphy8806x PHY in reset. 6810 * Parameters: 6811 * unit - BCM unit number. 6812 * port - Port number. 6813 * flags - Reason to stop 6814 * Returns: 6815 * SOC_E_XXX 6816 */ 6817 6818 int 6819 _8806x_notify_resume(int unit, soc_port_t port, uint32 flags) 6820 { 6821 EXT_PHY_SW_STATE(unit, port)->stop &= ~flags; 6822 return _8806x_stop(unit, port); 6823 } 6824 6825 /* 6826 * Function: 6827 * phy_8806x_diag_ctrl 6828 * Purpose: 6829 * xx 6830 * Parameters: 6831 * unit - BCM unit number. 6832 * port - Port number. 6833 6834 * Returns: 6835 * SOC_E_NONE 6836 */ 6837 6838 STATIC int 6839 phy_8806x_diag_ctrl( 6840 int unit, /* unit */ 6841 soc_port_t port, /* port */ 6842 uint32 inst, /* the specific device block the control action directs to */ 6843 int op_type, /* operation types: read,write or command sequence */ 6844 int op_cmd, /* command code */ 6845 void *arg) /* command argument based on op_type/op_cmd */ 6846 { 6847 int32 intf, prev_intf; 6848 phy_ctrl_t *pc; 6849 int rv = SOC_E_NONE; 6850 6851 /* locate phy control, phymod control, and the configuration data */ 6852 pc = EXT_PHY_SW_STATE(unit, port); 6853 if (pc == NULL) { 6854 return SOC_E_INTERNAL; 6855 } 6856 6857 /* Temporarily Set Interface type in PC flags, for the duration of this diag */ 6858 6859 intf = PHY_DIAG_INST_INTF(inst); 6860 if (intf == PHY_DIAG_INTF_DFLT) { 6861 intf = PHY_DIAG_INTF_LINE; 6862 } 6863 6864 prev_intf = (pc->flags & PHYCTRL_SYS_SIDE_CTRL) ? 1 : 0; 6865 6866 if (intf == PHY_DIAG_INTF_SYS) { 6867 pc->flags |= PHYCTRL_SYS_SIDE_CTRL; 6868 } else { 6869 pc->flags &= ~PHYCTRL_SYS_SIDE_CTRL; 6870 } 6871 6872 switch(op_cmd) { 6873 case PHY_DIAG_CTRL_DSC: 6874 LOG_INFO(BSL_LS_SOC_PHY, 6875 (BSL_META_U(unit, 6876 "phy_mt2_diag_ctrl: " 6877 "u=%d p=%d PHY_DIAG_CTRL_DSC 0x%x\n"), 6878 unit, port, PHY_DIAG_CTRL_DSC)); 6879 rv = phy8806x_uc_status_dump(unit, port, arg); 6880 break; 6881 case PHY_DIAG_CTRL_STATE_GENERIC: 6882 LOG_INFO(BSL_LS_SOC_PHY, 6883 (BSL_META_U(unit, 6884 "phy_mt2_diag_ctrl: " 6885 "u=%d p=%d PHY_DIAG_CTRL_STATE_GENERIC 0x%x\n"), 6886 unit, port, PHY_DIAG_CTRL_STATE_GENERIC)); 6887 rv = _phy8806x_dump_buffer(unit, port, (unsigned char *)arg); 6888 break; 6889 default: 6890 if (op_type == PHY_DIAG_CTRL_SET) { 6891 rv = phy_8806x_control_set(unit,port,op_cmd,PTR_TO_INT(arg)); 6892 } else if (op_type == PHY_DIAG_CTRL_GET) { 6893 rv = phy_8806x_control_get(unit,port,op_cmd,(uint32 *)arg); 6894 } 6895 break ; 6896 } 6897 6898 if (prev_intf) { 6899 pc->flags |= PHYCTRL_SYS_SIDE_CTRL; 6900 } else { 6901 pc->flags &= ~PHYCTRL_SYS_SIDE_CTRL; 6902 } 6903 6904 SOC_IF_ERROR_RETURN(rv); 6905 return (SOC_E_NONE); 6906 } 6907 6908 /* 6909 * Function: 6910 * phy_8806x_linkup 6911 * Purpose: 6912 * Link up handler 6913 * Parameters: 6914 * unit - StrataSwitch unit #. 6915 * port - StrataSwitch port #. 6916 * Returns: 6917 * SOC_E_NONE 6918 */ 6919 STATIC int 6920 phy_8806x_linkup(int unit, soc_port_t port) 6921 { 6922 return SOC_E_NONE; 6923 } 6924 6925 /* 6926 * Function: 6927 * phy_8806x_linkfault_get 6928 * Purpose: 6929 * Get layer2 connection status. 6930 * Parameters: 6931 * unit - StrataSwitch unit #. 6932 * port - StrataSwitch port #. 6933 * fault - address of memory to store link fault state. 6934 * Returns: 6935 * SOC_E_NONE 6936 */ 6937 6938 STATIC int 6939 phy_8806x_linkfault_get(int unit, soc_port_t port, int *fault) 6940 { 6941 int rv = SOC_E_NONE; 6942 phy_ctrl_t *pc; 6943 #if defined(INCLUDE_FCMAP) 6944 uint16 fault_st; 6945 #endif 6946 uint16 reg_val; 6947 6948 pc = EXT_PHY_SW_STATE(unit, port); 6949 6950 *fault = FALSE; /* Default return */ 6951 6952 #if defined(INCLUDE_FCMAP) 6953 if (pc->fcmap_enable) { 6954 rv = READ_FC_LINK_FAULT_REG(unit, pc, &fault_st); 6955 *fault = (fault_st & VS_MISC_STATUS_STATUS_BIT_MASK) ? TRUE: FALSE; 6956 return(rv); 6957 } 6958 #endif 6959 6960 rv = READ_ETH_LOCAL_FAULT_REG(unit, pc, ®_val); 6961 if (reg_val & VS_MISC_STATUS_LIVE_STATUS_BIT_MASK) { 6962 *fault |= SOC_PORT_FAULT_LOCAL; 6963 } 6964 6965 rv = READ_ETH_REMOTE_FAULT_REG(unit, pc, ®_val); 6966 if (reg_val & VS_MISC_STATUS_LIVE_STATUS_BIT_MASK) { 6967 *fault |= SOC_PORT_FAULT_REMOTE; 6968 } 6969 6970 return (rv); 6971 } 6972 6973 /* Utility functions */ 6974 6975 STATIC int 6976 _phy_8806x_write_to_arm(int unit, phy_ctrl_t *pc, uint32 addr, uint8 *data,int len) 6977 { 6978 int n_writes, i; 6979 6980 #ifdef PHY8806X_MEASSURE_DOWNLOAD_TIME 6981 sal_usecs_t t; 6982 t = sal_time_usecs(); 6983 #endif 6984 6985 n_writes = (len + WRITE_BLK_SIZE -1) / WRITE_BLK_SIZE; 6986 6987 for ( i = 0; i < n_writes; i++ ) { 6988 6989 /* address frames are ignored in the download mode */ 6990 SOC_IF_ERROR_RETURN 6991 (PHY8806X_REG_WRITE(unit, pc, 6992 SOC_PHY_CLAUSE45_ADDR(((1U << 3) | 0U), (((uint16)data[0])<<8)|data[1]), 6993 (((uint16)data[2])<<8)|data[3]) ); 6994 6995 data += WRITE_BLK_SIZE; 6996 6997 } 6998 6999 #ifdef PHY8806X_MEASSURE_DOWNLOAD_TIME 7000 LOG_CLI((BSL_META_U(unit, 7001 "u=%d p=%d raw download took %u us\n"), unit, pc->port, SAL_USECS_SUB(sal_time_usecs(), t))); 7002 #endif 7003 7004 return (SOC_E_NONE); 7005 } 7006 7007 7008 int 7009 phy_8806x_sbus_cmd(int unit,phy_ctrl_t *pc, uint32 reg, uint32 cmd, int ring, uint32 arg[]) 7010 { 7011 int count, rv, write, size; 7012 uint16 status, temp0, temp1; 7013 7014 size = ((cmd >> 7) & 0x7f) >> 2; 7015 7016 if ((size < 1) || (size > 4)) { 7017 return (SOC_E_PARAM); 7018 } 7019 7020 7021 if (ring > 0x2) { 7022 LOG_CLI((BSL_META_U(unit, 7023 "phy_8806x_sbus_reg_cmd: u=%d p=%d : invalid ring !." 7024 " \n"), unit, pc->port)); 7025 return (SOC_E_PARAM); 7026 } 7027 7028 ring &= 0x3; 7029 7030 /* LOG_CLI((BSL_META_U(unit, 7031 "phy_8806x_sbus_reg_cmd: u=%d p=%d cmd_reg=%08x" 7032 " \n"), unit, pc->port, cmd)); */ 7033 7034 write = (((cmd >> 26) & 0x3f) + 1) & 0x2; 7035 7036 SOC_IF_ERROR_RETURN 7037 (WRITE_PHY8806X_SBUS_COMMAND_UPPER_REG(unit, pc, (cmd >> 16) & 0xffff)); 7038 SOC_IF_ERROR_RETURN 7039 (WRITE_PHY8806X_SBUS_COMMAND_LOWER_REG(unit, pc, cmd & 0xffff)); 7040 7041 SOC_IF_ERROR_RETURN 7042 (WRITE_PHY8806X_SBUS_ADDR_UPPER_REG(unit, pc, (reg >> 16) & 0xffff)); 7043 SOC_IF_ERROR_RETURN 7044 (WRITE_PHY8806X_SBUS_ADDR_LOWER_REG(unit, pc, reg & 0xffff)); 7045 7046 if (write) { 7047 if (size-- > 0) { 7048 SOC_IF_ERROR_RETURN 7049 (WRITE_PHY8806X_SBUS_DATA_BYTES_1_0_REG(unit, pc, arg[0] & 0xffff)); 7050 SOC_IF_ERROR_RETURN 7051 (WRITE_PHY8806X_SBUS_DATA_BYTES_3_2_REG(unit, pc, (arg[0] >> 16) & 0xffff)); 7052 } 7053 7054 if (size-- > 0) { 7055 SOC_IF_ERROR_RETURN 7056 (WRITE_PHY8806X_SBUS_DATA_BYTES_5_4_REG(unit, pc, arg[1] & 0xffff)); 7057 SOC_IF_ERROR_RETURN 7058 (WRITE_PHY8806X_SBUS_DATA_BYTES_7_6_REG(unit, pc, (arg[1] >> 16) & 0xffff)); 7059 } 7060 7061 if (size-- > 0) { 7062 SOC_IF_ERROR_RETURN 7063 (WRITE_PHY8806X_SBUS_DATA_BYTES_9_8_REG(unit, pc, arg[2] & 0xffff)); 7064 SOC_IF_ERROR_RETURN 7065 (WRITE_PHY8806X_SBUS_DATA_BYTES_11_10_REG(unit, pc, (arg[2] >> 16) & 0xffff)); 7066 } 7067 7068 if (size-- > 0) { 7069 SOC_IF_ERROR_RETURN 7070 (WRITE_PHY8806X_SBUS_DATA_BYTES_13_12_REG(unit, pc, arg[3] & 0xffff)); 7071 SOC_IF_ERROR_RETURN 7072 (WRITE_PHY8806X_SBUS_DATA_BYTES_15_14_REG(unit, pc, (arg[3] >> 16) & 0xffff)); 7073 } 7074 } 7075 7076 SOC_IF_ERROR_RETURN 7077 (WRITE_PHY8806X_SBUS_CONTROL_REG(unit, pc, (1U << 15) | (ring << 12))); /* TOP + go */ 7078 7079 count = 0; 7080 7081 do { 7082 rv = READ_PHY8806X_SBUS_STATUS_REG(unit, pc, &status); 7083 if (((status & (SBUS_STATUS_ERR | SBUS_STATUS_NAK | SBUS_STATUS_DONE)) != 0) || 7084 SOC_FAILURE(rv)) { 7085 break; 7086 } 7087 } while (count++ < SCHAN_MAX_POLLS); 7088 7089 if (count >= SCHAN_MAX_POLLS) { 7090 LOG_CLI((BSL_META_U(unit, 7091 "phy_8806x_sbus_reg_cmd failed: u=%d p=%d status=%04x" 7092 "SCHAN_MAX_POLLS reached !.\n"), unit, pc->port, status)); 7093 return (SOC_E_FAIL); 7094 } 7095 7096 if ((status & (SBUS_STATUS_ERR | SBUS_STATUS_NAK)) != 0) { 7097 LOG_CLI((BSL_META_U(unit, 7098 "phy_8806x_sbus_reg_cmd failed: u=%d p=%d " 7099 "cmd=0x%04x reg=0x%08x ring=%d d[0]=0x%08x d[1]=0x%08x d[2]=0x%08x d[3]=0x%08x status=%04x\n"), unit, pc->port, cmd, reg, ring, arg[0], arg[1], arg[2], arg[3], status)); 7100 return (SOC_E_FAIL); 7101 } 7102 7103 if (!write) { 7104 7105 if (size-- > 0) { 7106 SOC_IF_ERROR_RETURN 7107 (READ_PHY8806X_SBUS_DATA_BYTES_1_0_REG(unit, pc, &temp0)); 7108 SOC_IF_ERROR_RETURN 7109 (READ_PHY8806X_SBUS_DATA_BYTES_3_2_REG(unit, pc, &temp1)); 7110 arg[0] = (((uint32) temp1) << 16) | temp0; 7111 } 7112 7113 if (size-- > 0) { 7114 SOC_IF_ERROR_RETURN 7115 (READ_PHY8806X_SBUS_DATA_BYTES_5_4_REG(unit, pc, &temp0)); 7116 SOC_IF_ERROR_RETURN 7117 (READ_PHY8806X_SBUS_DATA_BYTES_7_6_REG(unit, pc, &temp1)); 7118 arg[1] = (((uint32) temp1) << 16) | temp0; 7119 } 7120 7121 if (size-- > 0) { 7122 SOC_IF_ERROR_RETURN 7123 (READ_PHY8806X_SBUS_DATA_BYTES_9_8_REG(unit, pc, &temp0)); 7124 SOC_IF_ERROR_RETURN 7125 (READ_PHY8806X_SBUS_DATA_BYTES_11_10_REG(unit, pc, &temp1)); 7126 arg[2] = (((uint32) temp1) << 16) | temp0; 7127 } 7128 7129 if (size-- > 0) { 7130 SOC_IF_ERROR_RETURN 7131 (READ_PHY8806X_SBUS_DATA_BYTES_13_12_REG(unit, pc, &temp0)); 7132 SOC_IF_ERROR_RETURN 7133 (READ_PHY8806X_SBUS_DATA_BYTES_15_14_REG(unit, pc, &temp1)); 7134 arg[3] = (((uint32) temp1) << 16) | temp0; 7135 } 7136 } 7137 7138 return (SOC_E_NONE); 7139 } 7140 7141 STATIC int _pmd_enable(int unit, phy_ctrl_t *pc, int sys) 7142 { 7143 uint32 data[4], reg_cmd, reg_cmd_1, mem_cmd /* , reg_rcmd, reg_rcmd_1 */; 7144 int ring, rv; 7145 uint16 status = 0; 7146 7147 ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */ 7148 7149 reg_cmd = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x6 : 0x2) & 0x7f) << 19) |(4 << 7); 7150 reg_cmd_1 = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(4 << 7); 7151 mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7); 7152 7153 /* 7154 reg_rcmd = (SBUS_READ_REGISTER_CMD_MSG << 26) |(((sys ? 0x6 : 0x2) & 0x7f) << 19) |(4 << 7); 7155 reg_rcmd_1 = (SBUS_READ_REGISTER_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(4 << 7); 7156 */ 7157 7158 #if defined(INCLUDE_FCMAP) 7159 if (pc->fcmap_enable && !sys) { 7160 /* FCPORT_PLL0_CTRL_CONFIGr = 0x3 */ 7161 data[0] = 0x3; 7162 SOC_IF_ERROR_RETURN 7163 (phy_8806x_sbus_cmd(unit, pc, 0x02000f00, reg_cmd_1, ring, data)); 7164 7165 /* 7166 SOC_IF_ERROR_RETURN 7167 (phy_8806x_sbus_cmd(unit, pc, 0x02000f00, reg_rcmd_1, ring, data)); 7168 */ 7169 7170 /* FCPORT_PLL1_CTRL_CONFIGr = 0x1 */ 7171 data[0] = 0x1; 7172 SOC_IF_ERROR_RETURN 7173 (phy_8806x_sbus_cmd(unit, pc, 0x02001000, reg_cmd_1, ring, data)); 7174 /* 7175 SOC_IF_ERROR_RETURN 7176 (phy_8806x_sbus_cmd(unit, pc, 0x02001000, reg_rcmd_1, ring, data)); 7177 */ 7178 } 7179 #endif 7180 7181 /* CLPORT_POWER_SAVE = 0 */ 7182 data[0] = 0; 7183 SOC_IF_ERROR_RETURN 7184 (phy_8806x_sbus_cmd(unit, pc, 0x02020D00, reg_cmd, ring, data)); 7185 7186 /* CLPORT_XGXS0_CTRL_REG = 0x1C */ 7187 data[0] = 0x1C; 7188 SOC_IF_ERROR_RETURN 7189 (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring, data)); 7190 7191 /* CLPORT_XGXS0_CTRL_REG = 0x1E */ 7192 data[0] = 0x1e; 7193 SOC_IF_ERROR_RETURN 7194 (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring, data)); 7195 7196 /* CLPORT_XGXS0_CTRL_REG = 0x0E */ 7197 data[0] = 0x0e; 7198 SOC_IF_ERROR_RETURN 7199 (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring, data)); 7200 7201 sal_udelay(10000); 7202 /* CLPORT_XGXS0_CTRL_REG = 0x06 */ 7203 data[0] = 0x06; 7204 SOC_IF_ERROR_RETURN 7205 (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring, data)); 7206 7207 sal_udelay(10000); 7208 /* CLPORT_XGXS0_CTRL_REG = fc ? 0x7 : 0x5 */ 7209 data[0] = 0x5; 7210 #if defined(INCLUDE_FCMAP) 7211 if (pc->fcmap_enable) { 7212 data[0] = 0x7; 7213 } 7214 #endif 7215 SOC_IF_ERROR_RETURN 7216 (phy_8806x_sbus_cmd(unit, pc, 0x02021400, reg_cmd, ring, data)); 7217 7218 /* CLPORT_POWER_SAVE = 0 */ 7219 7220 /* FCPORT_TOP_CTRL_CONFIG = 0x10 */ 7221 data[0] = 0x10; 7222 SOC_IF_ERROR_RETURN 7223 (phy_8806x_sbus_cmd(unit, pc, 0x02000000, reg_cmd_1, ring, data)); 7224 7225 /* PMD_X1_CONTROL.[1:0] = 0x3 */ 7226 data[0] = PORT_ADDRESS(0x00009010, sys, ring); 7227 data[1] = 0x0003fffc; 7228 data[2] = 0x1; 7229 data[3] = 0; 7230 SOC_IF_ERROR_RETURN 7231 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7232 7233 /* RESET_CONTROL_PMD.0 = 0x0 core_s_rstb = 0x0 */ 7234 data[0] = PORT_ADDRESS(0x0800d101, sys, ring); 7235 data[1] = 0x0000fffe; 7236 data[2] = 0x1; 7237 data[3] = 0; 7238 SOC_IF_ERROR_RETURN 7239 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7240 7241 7242 /* RESET_CONTROL_PMD.0 = 0x1 core_s_rstb = 0x1 */ 7243 data[0] = PORT_ADDRESS(0x0800d101, sys, ring); 7244 data[1] = 0x0001fffe; 7245 data[2] = 0x1; 7246 data[3] = 0; 7247 SOC_IF_ERROR_RETURN 7248 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7249 7250 7251 /* PMD_X4_CONTROL.[1:0] = 0x3 */ 7252 data[0] = PORT_ADDRESS(0x0000c010, sys, ring); 7253 data[1] = 0x0003fffc; 7254 data[2] = 0x1; 7255 data[3] = 0; 7256 SOC_IF_ERROR_RETURN 7257 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7258 7259 /* new additions */ 7260 7261 /* MICRO_A_COM_CLOCK_CONTROL0.1 = 0x0, micro_core_clk_en = 0 */ 7262 data[0] = PORT_ADDRESS(0x0800d200, sys, ring); 7263 data[1] = 0x0000fffd; 7264 data[2] = 0x1; 7265 data[3] = 0; 7266 SOC_IF_ERROR_RETURN 7267 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7268 7269 /* MICRO_A_COM_CLOCK_CONTROL0.0 = 0x0, micro_master_clk_en = 0 */ 7270 data[0] = PORT_ADDRESS(0x0800d200, sys, ring); 7271 data[1] = 0x0000fffe; 7272 data[2] = 0x1; 7273 data[3] = 0; 7274 SOC_IF_ERROR_RETURN 7275 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7276 7277 7278 /* MICRO_C_ram_control0.1 = 1, micro_protect_fwcode = 1 */ 7279 data[0] = PORT_ADDRESS(0x0800d225, sys, ring); 7280 data[1] = 0x0002fffd; 7281 data[2] = 0x1; 7282 data[3] = 0; 7283 SOC_IF_ERROR_RETURN 7284 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7285 7286 7287 data[0] = PORT_ADDRESS(0x0800d200, sys, ring); 7288 data[1] = 0x00000000; 7289 data[2] = 0x1; 7290 data[3] = 0; 7291 SOC_IF_ERROR_RETURN 7292 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7293 7294 data[0] = PORT_ADDRESS(0x0800d201, sys, ring); 7295 data[1] = 0x00000000; 7296 data[2] = 0x1; 7297 data[3] = 0; 7298 SOC_IF_ERROR_RETURN 7299 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7300 7301 data[0] = PORT_ADDRESS(0x0800d202, sys, ring); 7302 data[1] = 0x00000000; 7303 data[2] = 0x1; 7304 data[3] = 0; 7305 SOC_IF_ERROR_RETURN 7306 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7307 7308 7309 data[0] = PORT_ADDRESS(0x0800d203, sys, ring); 7310 data[1] = 0x00000000; 7311 data[2] = 0x1; 7312 data[3] = 0; 7313 SOC_IF_ERROR_RETURN 7314 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7315 7316 7317 data[0] = PORT_ADDRESS(0x0800d204, sys, ring); 7318 data[1] = 0x00000000; 7319 data[2] = 0x1; 7320 data[3] = 0; 7321 SOC_IF_ERROR_RETURN 7322 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7323 7324 7325 data[0] = PORT_ADDRESS(0x0800d205, sys, ring); 7326 data[1] = 0x00000000; 7327 data[2] = 0x1; 7328 data[3] = 0; 7329 SOC_IF_ERROR_RETURN 7330 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7331 7332 7333 data[0] = PORT_ADDRESS(0x0800d206, sys, ring); 7334 data[1] = 0x00000000; 7335 data[2] = 0x1; 7336 data[3] = 0; 7337 SOC_IF_ERROR_RETURN 7338 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7339 7340 7341 data[0] = PORT_ADDRESS(0x0800d207, sys, ring); 7342 data[1] = 0x00000000; 7343 data[2] = 0x1; 7344 data[3] = 0; 7345 SOC_IF_ERROR_RETURN 7346 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7347 7348 7349 data[0] = PORT_ADDRESS(0x0800d208, sys, ring); 7350 data[1] = 0x00000000; 7351 data[2] = 0x1; 7352 data[3] = 0; 7353 SOC_IF_ERROR_RETURN 7354 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7355 7356 7357 data[0] = PORT_ADDRESS(0x0800d209, sys, ring); 7358 data[1] = 0x00000000; 7359 data[2] = 0x1; 7360 data[3] = 0; 7361 SOC_IF_ERROR_RETURN 7362 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7363 7364 7365 data[0] = PORT_ADDRESS(0x0800d20a, sys, ring); 7366 data[1] = 0x00000000; 7367 data[2] = 0x1; 7368 data[3] = 0; 7369 SOC_IF_ERROR_RETURN 7370 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7371 7372 7373 data[0] = PORT_ADDRESS(0x0800d20b, sys, ring); 7374 data[1] = 0x00000000; 7375 data[2] = 0x1; 7376 data[3] = 0; 7377 SOC_IF_ERROR_RETURN 7378 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7379 7380 7381 data[0] = PORT_ADDRESS(0x0800d20c, sys, ring); 7382 data[1] = 0x00000000; 7383 data[2] = 0x1; 7384 data[3] = 0; 7385 SOC_IF_ERROR_RETURN 7386 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7387 7388 7389 data[0] = PORT_ADDRESS(0x0800d20d, sys, ring); 7390 data[1] = 0x00000000; 7391 data[2] = 0x1; 7392 data[3] = 0; 7393 SOC_IF_ERROR_RETURN 7394 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7395 7396 7397 data[0] = PORT_ADDRESS(0x0800d20e, sys, ring); 7398 data[1] = 0x00000000; 7399 data[2] = 0x1; 7400 data[3] = 0; 7401 SOC_IF_ERROR_RETURN 7402 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7403 7404 7405 data[0] = PORT_ADDRESS(0x0800d20f, sys, ring); 7406 data[1] = 0x00000000; 7407 data[2] = 0x1; 7408 data[3] = 0; 7409 SOC_IF_ERROR_RETURN 7410 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7411 7412 7413 data[0] = PORT_ADDRESS(0x0800d210, sys, ring); 7414 data[1] = 0x00000000; 7415 data[2] = 0x1; 7416 data[3] = 0; 7417 SOC_IF_ERROR_RETURN 7418 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7419 7420 7421 data[0] = PORT_ADDRESS(0x0800d211, sys, ring); 7422 data[1] = 0x00000000; 7423 data[2] = 0x1; 7424 data[3] = 0; 7425 SOC_IF_ERROR_RETURN 7426 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7427 7428 7429 data[0] = PORT_ADDRESS(0x0800d212, sys, ring); 7430 data[1] = 0x00000000; 7431 data[2] = 0x1; 7432 data[3] = 0; 7433 SOC_IF_ERROR_RETURN 7434 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7435 7436 7437 data[0] = PORT_ADDRESS(0x0800d213, sys, ring); 7438 data[1] = 0x00000000; 7439 data[2] = 0x1; 7440 data[3] = 0; 7441 SOC_IF_ERROR_RETURN 7442 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7443 7444 7445 data[0] = PORT_ADDRESS(0x0800d214, sys, ring); 7446 data[1] = 0x00000000; 7447 data[2] = 0x1; 7448 data[3] = 0; 7449 SOC_IF_ERROR_RETURN 7450 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7451 7452 7453 data[0] = PORT_ADDRESS(0x0800d215, sys, ring); 7454 data[1] = 0x00000000; 7455 data[2] = 0x1; 7456 data[3] = 0; 7457 SOC_IF_ERROR_RETURN 7458 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7459 7460 7461 data[0] = PORT_ADDRESS(0x0800d216, sys, ring); 7462 data[1] = 0x00070000; 7463 data[2] = 0x1; 7464 data[3] = 0; 7465 SOC_IF_ERROR_RETURN 7466 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7467 7468 7469 data[0] = PORT_ADDRESS(0x0800d217, sys, ring); 7470 data[1] = 0x00000000; 7471 data[2] = 0x1; 7472 data[3] = 0; 7473 SOC_IF_ERROR_RETURN 7474 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7475 7476 7477 data[0] = PORT_ADDRESS(0x0800d218, sys, ring); 7478 data[1] = 0x00000000; 7479 data[2] = 0x1; 7480 data[3] = 0; 7481 SOC_IF_ERROR_RETURN 7482 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7483 7484 7485 data[0] = PORT_ADDRESS(0x0800d219, sys, ring); 7486 data[1] = 0x00000000; 7487 data[2] = 0x1; 7488 data[3] = 0; 7489 SOC_IF_ERROR_RETURN 7490 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7491 7492 7493 data[0] = PORT_ADDRESS(0x0800d21a, sys, ring); 7494 data[1] = 0x00000000; 7495 data[2] = 0x1; 7496 data[3] = 0; 7497 SOC_IF_ERROR_RETURN 7498 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7499 7500 7501 data[0] = PORT_ADDRESS(0x0800d21b, sys, ring); 7502 data[1] = 0x00000000; 7503 data[2] = 0x1; 7504 data[3] = 0; 7505 SOC_IF_ERROR_RETURN 7506 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7507 7508 7509 data[0] = PORT_ADDRESS(0x0800d220, sys, ring); 7510 data[1] = 0x00000000; 7511 data[2] = 0x1; 7512 data[3] = 0; 7513 SOC_IF_ERROR_RETURN 7514 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7515 7516 7517 data[0] = PORT_ADDRESS(0x0800d221, sys, ring); 7518 data[1] = 0x00000000; 7519 data[2] = 0x1; 7520 data[3] = 0; 7521 SOC_IF_ERROR_RETURN 7522 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7523 7524 7525 data[0] = PORT_ADDRESS(0x0800d224, sys, ring); 7526 data[1] = 0x00000000; 7527 data[2] = 0x1; 7528 data[3] = 0; 7529 SOC_IF_ERROR_RETURN 7530 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7531 7532 7533 data[0] = PORT_ADDRESS(0x0800d226, sys, ring); 7534 data[1] = 0x00000000; 7535 data[2] = 0x1; 7536 data[3] = 0; 7537 SOC_IF_ERROR_RETURN 7538 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7539 7540 7541 data[0] = PORT_ADDRESS(0x0800d225, sys, ring); 7542 data[1] = 0x88030000; 7543 data[2] = 0x1; 7544 data[3] = 0; 7545 SOC_IF_ERROR_RETURN 7546 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7547 7548 7549 data[0] = PORT_ADDRESS(0x0800d228, sys, ring); 7550 data[1] = 0x01010000; 7551 data[2] = 0x1; 7552 data[3] = 0; 7553 SOC_IF_ERROR_RETURN 7554 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7555 7556 7557 data[0] = PORT_ADDRESS(0x0800d229, sys, ring); 7558 data[1] = 0x00000000; 7559 data[2] = 0x1; 7560 data[3] = 0; 7561 SOC_IF_ERROR_RETURN 7562 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7563 7564 7565 7566 /* MICRO_C_ram_control0.1 = 1, micro_protect_fwcode = 0 */ 7567 data[0] = PORT_ADDRESS(0x0800d225, sys, ring); 7568 data[1] = 0x0000fffd; 7569 data[2] = 0x1; 7570 data[3] = 0; 7571 SOC_IF_ERROR_RETURN 7572 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7573 7574 /* end of new additions */ 7575 7576 #if 0 7577 /* CKRST_CTRL_PMD_LANE_RESET_N_PWRDN_PIN_KILL_CONTROL.0 = 0x1 */ 7578 data[0] = PORT_ADDRESS(0x0800d0b3, sys, ring); 7579 data[1] = 0x0001fffe; 7580 data[2] = 0x1; 7581 data[3] = 0; 7582 SOC_IF_ERROR_RETURN 7583 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7584 #endif 7585 7586 /* MICRO_A_COM_CLOCK_CONTROL0.0 = 0x1 micro_master_clk_en = 0x1 */ 7587 data[0] = PORT_ADDRESS(0x0800d200, sys, ring); 7588 data[1] = 0x0001fffe; 7589 data[2] = 0x1; 7590 data[3] = 0; 7591 SOC_IF_ERROR_RETURN 7592 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7593 7594 /* MICRO_A_COM_RESET_CONTROL0.0 = 0x0, MICRO_A_COM_RESET_CONTROL0.3 = 0x0, micro_pram_if_rstb=0 micro_master_rstb= 0x0 */ 7595 data[0] = PORT_ADDRESS(0x0800d201, sys, ring); 7596 data[1] = 0x0000fff6; 7597 data[2] = 0x1; 7598 data[3] = 0; 7599 SOC_IF_ERROR_RETURN 7600 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7601 7602 /* MICRO_A_COM_RESET_CONTROL0.0 = 0x1, MICRO_A_COM_RESET_CONTROL0.3 = 0x1, micro_pram_if_rstb=1 micro_master_rstb= 0x1 */ 7603 data[0] = PORT_ADDRESS(0x0800d201, sys, ring); 7604 data[1] = 0x0009fff6; 7605 data[2] = 0x1; 7606 data[3] = 0; 7607 SOC_IF_ERROR_RETURN 7608 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7609 7610 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 7611 /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x1 */ 7612 data[0] = PORT_ADDRESS(0x0800d202, sys, ring); 7613 data[1] = 0x0100fcff; 7614 data[2] = 0x1; 7615 data[3] = 0; 7616 SOC_IF_ERROR_RETURN 7617 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7618 7619 /* tsc_reg_read_test_base(unit, pc->port, sys, 1, 0, 0xd203); */ 7620 7621 /* sal_udelay(250000); */ 7622 7623 soc_timeout_init(&TO(pc), 250000, 0); /* 250ms timer */ 7624 7625 do { 7626 7627 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + (sys ? 9 : 1), 1, 0, 0xd203, &status); 7628 if (SOC_FAILURE(rv)) { 7629 break; 7630 } 7631 if ((status & 0x1) == 0x1) { 7632 break; 7633 } 7634 } while (!soc_timeout_check(&TO(pc))); 7635 7636 if ((status & 0x1) != 0x1) { 7637 LOG_CLI((BSL_META_U(unit, 7638 "PHY8806X PMD (%s) failed to clear code RAM: u=%d p=%d status=%04x" 7639 " !.\n"), sys ? "sys" : "line", unit, pc->port, status)); 7640 } 7641 7642 /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x0 */ 7643 data[0] = PORT_ADDRESS(0x0800d202, sys, ring); 7644 data[1] = 0x0000fcff; 7645 data[2] = 0x1; 7646 data[3] = 0; 7647 SOC_IF_ERROR_RETURN 7648 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7649 7650 /* MICRO_A_COM_AHB_CONTROL0.[1:0] = 0x2, micro_ra_wrdatasize = 0x2 (32-bit) */ 7651 data[0] = PORT_ADDRESS(0x0800d202, sys, ring); 7652 data[1] = 0x0002fffc; 7653 data[2] = 0x1; 7654 data[3] = 0; 7655 SOC_IF_ERROR_RETURN 7656 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7657 } 7658 7659 /* MICRO_A_COM_PRAMIF_CONTROL0.0 = 0x1 , micro_pramif_en = 1 */ 7660 data[0] = PORT_ADDRESS(0x0800d20c, sys, ring); 7661 data[1] = 0x0001fffe; 7662 data[2] = 0x1; 7663 data[3] = 0; 7664 SOC_IF_ERROR_RETURN 7665 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7666 7667 if (FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART)) { 7668 /* No need to set UCMEM_ACCESS_CONTROL=1 if no f/w is downloaded */ 7669 return (SOC_E_NONE); 7670 } 7671 7672 /* FCPORT_TOP_CTRL_CONFIG = 0x11 */ 7673 data[0] = 0x11; 7674 SOC_IF_ERROR_RETURN 7675 (phy_8806x_sbus_cmd(unit, pc, 0x02000000, reg_cmd_1, ring, data)); 7676 7677 return (SOC_E_NONE); 7678 } 7679 7680 STATIC int _pmd_disable(int unit, phy_ctrl_t *pc, int sys) 7681 { 7682 uint32 data[4], /* reg_cmd, */ reg_cmd_1, mem_cmd; 7683 int ring, rv; 7684 uint16 status = 0; 7685 7686 ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */ 7687 7688 /* reg_cmd = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x6 : 0x2) & 0x7f) << 19) |(4 << 7); */ 7689 reg_cmd_1 = (SBUS_WRITE_REGISTER_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(4 << 7); 7690 mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7); 7691 7692 if (!(FLAGS(pc) & (PHY8806X_MODE_CHANGE | PHY8806X_FW_RESTART))) { 7693 /* FCPORT_TOP_CTRL_CONFIG = 0x10 */ 7694 data[0] = 0x10; 7695 SOC_IF_ERROR_RETURN 7696 (phy_8806x_sbus_cmd(unit, pc, 0x02000000, reg_cmd_1, ring, data)); 7697 } 7698 7699 /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x2, clear data ram */ 7700 data[0] = PORT_ADDRESS(0x0800d202, sys, ring); 7701 data[1] = 0x0200fcff; 7702 data[2] = 0x1; 7703 data[3] = 0; 7704 SOC_IF_ERROR_RETURN 7705 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7706 7707 /* tsc_reg_read_test_base(unit, pc->port, sys, 1, 0, 0xd203); */ 7708 7709 /* sal_udelay(250000); */ 7710 7711 soc_timeout_init(&TO(pc), 250000, 0); /* 250ms timer */ 7712 7713 do { 7714 rv = _tsc_reg_read(unit, pc, 0, (pc->phy_id & 0x7) + (sys ? 9 : 1), 1, 0, 0xd203, &status); 7715 if (SOC_FAILURE(rv)) { 7716 break; 7717 } 7718 if ((status & 0x1) == 0x1) { 7719 break; 7720 } 7721 } while (!soc_timeout_check(&TO(pc))); 7722 7723 if ((status & 0x1) != 0x1) { 7724 LOG_CLI((BSL_META_U(unit, 7725 "PHY8806X PMD (%s) failed to clear data RAM: u=%d p=%d status=%04x" 7726 " !.\n"), sys ? "sys" : "line", unit, pc->port, status)); 7727 } 7728 7729 /* MICRO_A_COM_AHB_CONTROL0.[9:8] = 0x0 */ 7730 data[0] = PORT_ADDRESS(0x0800d202, sys, ring); 7731 data[1] = 0x0000fcff; 7732 data[2] = 0x1; 7733 data[3] = 0; 7734 SOC_IF_ERROR_RETURN 7735 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7736 7737 7738 /* CKRST_CTRL_PMD_LANE_RESET_N_PWRDN_PIN_KILL_CONTROL.0 = 0x1 */ 7739 data[0] = PORT_ADDRESS(0x0800d0b3, sys, ring); 7740 data[1] = 0x0001fffe; 7741 data[2] = 0x1; 7742 data[3] = 0; 7743 SOC_IF_ERROR_RETURN 7744 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7745 7746 return (SOC_E_NONE); 7747 } 7748 7749 STATIC int _pmd_start(int unit, phy_ctrl_t *pc, int sys) 7750 { 7751 uint32 data[4], mem_cmd; 7752 int ring; 7753 7754 ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */ 7755 7756 mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG << 26) |(((sys ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7); 7757 7758 /* TOP_USER_CONTROL_0.15 = 0x0 */ 7759 data[0] = PORT_ADDRESS(0x0800d104, sys, ring); 7760 data[1] = 0x00007fff; 7761 data[2] = 0x1; 7762 data[3] = 0; 7763 SOC_IF_ERROR_RETURN 7764 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7765 7766 7767 /* TOP_USER_CONTROL_0.15 = 0x1 */ 7768 data[0] = PORT_ADDRESS(0x0800d104, sys, ring); 7769 data[1] = 0x80007fff; 7770 data[2] = 0x1; 7771 data[3] = 0; 7772 SOC_IF_ERROR_RETURN 7773 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7774 7775 7776 /* CKRST_CTRL_PMD_LANE_RESET_N_PWRDN_PIN_KILL_CONTROL.0 = 0x0 */ 7777 data[0] = PORT_ADDRESS(0x0800d0b3, sys, ring); 7778 data[1] = 0x0000fffe; 7779 data[2] = 0x1; 7780 data[3] = 0; 7781 SOC_IF_ERROR_RETURN 7782 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7783 7784 /* MICRO_A_COM_CLOCK_CONTROL0.1 = 0x1 */ 7785 data[0] = PORT_ADDRESS(0x0800d200, sys, ring); 7786 data[1] = 0x0002fffd; 7787 data[2] = 0x1; 7788 data[3] = 0; 7789 SOC_IF_ERROR_RETURN 7790 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7791 7792 /* MICRO_A_COM_RESET_CONTROL0.1 = 0x1 */ 7793 data[0] = PORT_ADDRESS(0x0800d201, sys, ring); 7794 data[1] = 0x0002fffd; 7795 data[2] = 0x1; 7796 data[3] = 0; 7797 SOC_IF_ERROR_RETURN 7798 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 7799 7800 return (SOC_E_NONE); 7801 } 7802 7803 7804 /* _phy_8806x_toplvl_sbus_{read|write}() need to be optimized when the data only transactions are 7805 implemented in the CMIC MDIO code. 7806 */ 7807 7808 int 7809 _phy_8806x_toplvl_sbus_write(int unit,phy_ctrl_t *pc, uint32 reg, uint32 arg[], int size) 7810 { 7811 uint32 cmd; 7812 7813 if ((size < 1) || (size > 4)) { 7814 return (SOC_E_PARAM); 7815 } 7816 7817 cmd = (SBUS_WRITE_REGISTER_CMD_MSG << 26) | 7818 ((montreal2_BLKTYPE_TOP & 0x7f) << 19) | 7819 ((4 * size) << 7); 7820 7821 return (phy_8806x_sbus_cmd(unit, pc, reg, cmd, 2, arg)); 7822 7823 } 7824 7825 int 7826 _phy_8806x_fcport_sbus_write(int unit,phy_ctrl_t *pc, int sys, uint32 reg, uint32 arg[], int size) 7827 { 7828 uint32 cmd, blk, addr; 7829 int ring; 7830 7831 if ((size < 1) || (size > 4)) { 7832 return (SOC_E_PARAM); 7833 } 7834 7835 blk = sys ? montreal2_BLKTYPE_SYS_FCPORT : montreal2_BLKTYPE_LINE_FCPORT; 7836 addr = reg & 0x03ffffff; 7837 addr |= ((blk & 0x3f) << 26); 7838 7839 /* Ports 0-3 = MIG0, 4-7 = MIG1 */ 7840 ring = ((pc->phy_id % 8) < 4) ? 0 : 1; 7841 7842 cmd = (SBUS_WRITE_REGISTER_CMD_MSG << 26) | 7843 ((blk & 0x7f) << 19) | 7844 ((4 * size) << 7); 7845 7846 return (phy_8806x_sbus_cmd(unit, pc, addr, cmd, ring, arg)); 7847 7848 } 7849 7850 int 7851 _sbus_write_test(int unit,int port, uint32 reg, uint32 value) 7852 { 7853 phy_ctrl_t *pc; 7854 uint32 temp32 = value; 7855 int rv; 7856 7857 pc = EXT_PHY_SW_STATE(unit, port); 7858 rv = _phy_8806x_toplvl_sbus_write(unit, pc, reg, &temp32, 1); 7859 7860 return rv; 7861 } 7862 7863 int 7864 _phy_8806x_toplvl_sbus_read(int unit,phy_ctrl_t *pc, uint32 reg, uint32 arg[], int size) 7865 { 7866 uint32 cmd; 7867 7868 if ((size < 1) || (size > 4)) { 7869 return (SOC_E_PARAM); 7870 } 7871 7872 cmd = (SBUS_READ_REGISTER_CMD_MSG << 26) | 7873 ((montreal2_BLKTYPE_TOP & 0x7f) << 19) | 7874 ((4 * size) << 7); 7875 7876 return (phy_8806x_sbus_cmd(unit, pc, reg, cmd, 2, arg)); 7877 } 7878 7879 #if defined(INCLUDE_FCMAP) 7880 int 7881 _phy_8806x_fcport_sbus_read(int unit,phy_ctrl_t *pc, int sys, uint32 reg, uint32 arg[], int size) 7882 { 7883 uint32 cmd, blk, addr; 7884 int ring; 7885 7886 if ((size < 1) || (size > 4)) { 7887 return (SOC_E_PARAM); 7888 } 7889 7890 blk = sys ? montreal2_BLKTYPE_SYS_FCPORT : montreal2_BLKTYPE_LINE_FCPORT; 7891 addr = reg & 0x03ffffff; 7892 addr |= ((blk & 0x3f) << 26); 7893 7894 /* Ports 0-3 = MIG0, 4-7 = MIG1 */ 7895 ring = ((pc->phy_id % 8) < 4) ? 0 : 1; 7896 7897 cmd = (SBUS_READ_REGISTER_CMD_MSG << 26) | 7898 ((blk & 0x7f) << 19) | 7899 ((4 * size) << 7); 7900 7901 return (phy_8806x_sbus_cmd(unit, pc, addr, cmd, ring, arg)); 7902 } 7903 #endif 7904 7905 int 7906 _sbus_read_test(int unit,int port, uint32 reg) 7907 { 7908 phy_ctrl_t *pc; 7909 uint32 temp32; 7910 int rv; 7911 7912 pc = EXT_PHY_SW_STATE(unit, port); 7913 rv = _phy_8806x_toplvl_sbus_read(unit, pc, reg, &temp32, 1); 7914 7915 LOG_CLI((BSL_META_U(unit, 7916 "_sbus_read_test: u=%d p=%d " 7917 "value=0x%08x\n"), unit, pc->port, temp32)); 7918 return rv; 7919 } 7920 7921 int 7922 _phy_8806x_write_top_soft_reset_reg(int unit, phy_ctrl_t *pc, uint32 val) 7923 { 7924 uint32 temp = val; 7925 int rv; 7926 rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_SOFT_RESET_REGr, &temp, 1); 7927 return (rv); 7928 } 7929 7930 int 7931 _phy_8806x_write_top_rts_misc_ctrl_reg(int unit, phy_ctrl_t *pc, uint32 val) 7932 { 7933 uint32 temp = val; 7934 int rv; 7935 rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_RTS_MISC_CTRLr, &temp, 1); 7936 return (rv); 7937 } 7938 7939 int 7940 _phy_8806x_write_top_soft_reset_reg_2(int unit, phy_ctrl_t *pc, uint32 val) 7941 { 7942 uint32 temp = val; 7943 int rv; 7944 rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_SOFT_RESET_REG_2r, &temp, 1); 7945 return (rv); 7946 } 7947 7948 int 7949 _phy_8806x_write_top_fc_mode_control_reg(int unit, phy_ctrl_t *pc, uint32 val) 7950 { 7951 uint32 temp = val; 7952 int rv; 7953 rv = _phy_8806x_toplvl_sbus_write(unit, pc, montreal2_TOP_FC_MODE_CONTROLr, &temp, 1); 7954 return (rv); 7955 } 7956 7957 int 7958 _phy_8806x_write_fcport_ext_tx_disable_ctrl(int unit, phy_ctrl_t *pc, int sys, uint32 val) 7959 { 7960 uint32 temp = val; 7961 int rv; 7962 rv = _phy_8806x_fcport_sbus_write(unit, pc, sys, montreal2_FCPORT_EXT_TX_DISABLE_CTRLr, &temp, 1); 7963 return (rv); 7964 } 7965 7966 int 7967 _fwdl_test(int unit,int port) 7968 { 7969 phy_ctrl_t *pc; 7970 7971 pc = EXT_PHY_SW_STATE(unit, port); 7972 7973 SOC_IF_ERROR_RETURN 7974 (_phy_8806x_write_to_arm(unit, pc, 0, FIRMWARE(pc), FIRMWARE_LEN(pc))); 7975 7976 return (SOC_E_NONE); 7977 } 7978 7979 7980 /* _phy_8806x_axi_{read|write}() need to be optimized when the data only transactions are 7981 implemented in the CMIC MDIO code. 7982 */ 7983 7984 STATIC int 7985 _phy_8806x_axi_write(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size) 7986 { 7987 int count, rv, i; 7988 uint16 control, status; 7989 uint32 temp32; 7990 7991 if ( addr & 0x3 ) { 7992 LOG_CLI((BSL_META_U(unit, 7993 "_phy_8806x_axi_write failed: u=%d p=%d " 7994 "addr=%08x - unaligned !.\n"), unit, pc->port, addr)); 7995 return (SOC_E_FAIL); 7996 } 7997 7998 SOC_IF_ERROR_RETURN 7999 (WRITE_PHY8806X_AXI_ADDR_UPPER_FX_REG(unit, pc, (addr >> 16) & 0xffff)); 8000 SOC_IF_ERROR_RETURN 8001 (WRITE_PHY8806X_AXI_ADDR_LOWER_FX_REG(unit, pc, addr & 0xffff)); 8002 8003 i = 0; 8004 while (size-- > 0) { 8005 /* 8006 When the current destination address is 8 byte aligned write to AXI_DATA_BYTES_1_2_FX_REG and 8007 AXI_DATA_BYTES_3_4_FX_REG else write to AXI_DATA_BYTES_5_6_FX_REG and AXI_DATA_BYTES_7_8_FX_REG. 8008 */ 8009 /* The following preserves the byte order. */ 8010 temp32 = HOST2LE32(data[i]); 8011 8012 if ( (addr + (i << 2)) & 0x7 ) { 8013 SOC_IF_ERROR_RETURN 8014 (WRITE_PHY8806X_AXI_DATA_BYTES_5_4_FX_REG(unit, pc, temp32 & 0xffff)); 8015 SOC_IF_ERROR_RETURN 8016 (WRITE_PHY8806X_AXI_DATA_BYTES_7_6_FX_REG(unit, pc, (temp32 >> 16) & 0xffff)); 8017 } else { 8018 SOC_IF_ERROR_RETURN 8019 (WRITE_PHY8806X_AXI_DATA_BYTES_1_0_FX_REG(unit, pc, temp32 & 0xffff)); 8020 SOC_IF_ERROR_RETURN 8021 (WRITE_PHY8806X_AXI_DATA_BYTES_3_2_FX_REG(unit, pc, (temp32 >> 16) & 0xffff)); 8022 } 8023 8024 SOC_IF_ERROR_RETURN 8025 (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (1U << 13))); /* pre-go */ 8026 8027 SOC_IF_ERROR_RETURN 8028 (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (5U << 13))); /* go */ 8029 8030 count = 0; 8031 8032 do { 8033 rv = READ_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, &control); 8034 if (((control & (1U << 15) ) == 0) || 8035 SOC_FAILURE(rv)) { 8036 break; 8037 } 8038 } while (count++ < AXI_MAX_POLLS); 8039 8040 rv = READ_PHY8806X_AXI_STATUS_FX_REG(unit, pc, &status); 8041 8042 if (count >= AXI_MAX_POLLS) { 8043 LOG_CLI((BSL_META_U(unit, 8044 "_phy_8806x_axi_write failed: u=%d p=%d addr=0x%08x control=0x%04x status=0x%04x" 8045 "AXI_MAX_POLLS reached !.\n"), unit, pc->port, addr + (i << 2), control, status)); 8046 return (SOC_E_FAIL); 8047 } 8048 8049 if ((status & (1U << 9)) != 0) { 8050 LOG_CLI((BSL_META_U(unit, 8051 "_phy_8806x_axi_write failed: u=%d p=%d " 8052 "addr=0x%08x status=0x%04x\n"), unit, pc->port, addr + (i << 2), status)); 8053 return (SOC_E_FAIL); 8054 } 8055 i++; 8056 } 8057 8058 return (SOC_E_NONE); 8059 } 8060 8061 int 8062 _axi_write_test(int unit,int port, uint32 reg, uint32 value) 8063 { 8064 phy_ctrl_t *pc; 8065 uint32 temp32 = value; 8066 int rv; 8067 8068 pc = EXT_PHY_SW_STATE(unit, port); 8069 rv = _phy_8806x_axi_write(unit, pc, reg, &temp32, 1); 8070 8071 return rv; 8072 } 8073 8074 int 8075 _axi_write_test2(int unit,int port, uint32 reg, uint32 value) 8076 { 8077 phy_ctrl_t *pc; 8078 uint32 temp32[2]; 8079 int rv; 8080 8081 temp32[0] = value; 8082 temp32[1] = value ^ 0xffffffff; 8083 8084 pc = EXT_PHY_SW_STATE(unit, port); 8085 rv = _phy_8806x_axi_write(unit, pc, reg, temp32, 2); 8086 8087 LOG_CLI((BSL_META_U(unit, 8088 "_sbus_read_test 2: u=%d p=%d " 8089 "temp32[0]=0x%08x temp32[1]=0x%08x\n"), unit, pc->port, temp32[0], temp32[1])); 8090 return rv; 8091 } 8092 8093 STATIC int 8094 _phy_8806x_axi_read(int unit,phy_ctrl_t *pc, uint32 addr, uint32 data[], int size) 8095 { 8096 int count, rv, i; 8097 uint16 control, status; 8098 uint16 temp0, temp1; 8099 uint32 temp32; 8100 8101 if ( addr & 0x3 ) { 8102 LOG_CLI((BSL_META_U(unit, 8103 "_phy_8806x_axi_read failed: u=%d p=%d " 8104 "addr=%08x - unaligned !.\n"), unit, pc->port, addr)); 8105 return (SOC_E_FAIL); 8106 } 8107 8108 SOC_IF_ERROR_RETURN 8109 (WRITE_PHY8806X_AXI_ADDR_UPPER_FX_REG(unit, pc, (addr >> 16) & 0xffff)); 8110 SOC_IF_ERROR_RETURN 8111 (WRITE_PHY8806X_AXI_ADDR_LOWER_FX_REG(unit, pc, addr & 0xffff)); 8112 8113 i = 0; 8114 while (size-- > 0) { 8115 SOC_IF_ERROR_RETURN 8116 (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (3U << 13))); /* pre-go */ 8117 8118 SOC_IF_ERROR_RETURN 8119 (WRITE_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, (7U << 13))); /* go */ 8120 8121 count = 0; 8122 8123 do { 8124 rv = READ_PHY8806X_AXI_CONTROL_FX_REG(unit, pc, &control); 8125 if (((control & (1U << 15)) == 0) || 8126 SOC_FAILURE(rv)) { 8127 break; 8128 } 8129 } while (count++ < AXI_MAX_POLLS); 8130 8131 rv = READ_PHY8806X_AXI_STATUS_FX_REG(unit, pc, &status); 8132 8133 if (count >= AXI_MAX_POLLS) { 8134 LOG_CLI((BSL_META_U(unit, 8135 "_phy_8806x_axi_read failed: u=%d p=%d addr=0x%08x control=0x%04x status=0x%04x\n" 8136 "AXI_MAX_POLLS reached !.\n"), unit, pc->port, addr + (i << 2), control, status)); 8137 return (SOC_E_FAIL); 8138 } 8139 8140 if ((status & (1U << 9)) != 0) { 8141 LOG_CLI((BSL_META_U(unit, 8142 "_phy_8806x_axi_read failed: u=%d p=%d " 8143 "addr=0x%08x status=0x%04x\n"), unit, pc->port, addr + (i << 2), status)); 8144 return (SOC_E_FAIL); 8145 } 8146 8147 /* 8148 When the current source address is 8 byte aligned read from AXI_DATA_BYTES_1_2_FX_REG and 8149 AXI_DATA_BYTES_3_4_FX_REG else read from AXI_DATA_BYTES_5_6_FX_REG and AXI_DATA_BYTES_7_8_FX_REG. 8150 */ 8151 if ( (addr + (i << 2)) & 0x7 ) { 8152 SOC_IF_ERROR_RETURN 8153 (READ_PHY8806X_AXI_DATA_BYTES_5_4_FX_REG(unit, pc, &temp0)); 8154 SOC_IF_ERROR_RETURN 8155 (READ_PHY8806X_AXI_DATA_BYTES_7_6_FX_REG(unit, pc, &temp1)); 8156 } else { 8157 SOC_IF_ERROR_RETURN 8158 (READ_PHY8806X_AXI_DATA_BYTES_1_0_FX_REG(unit, pc, &temp0)); 8159 SOC_IF_ERROR_RETURN 8160 (READ_PHY8806X_AXI_DATA_BYTES_3_2_FX_REG(unit, pc, &temp1)); 8161 } 8162 temp32 = (((uint32) temp1) << 16) | temp0; 8163 8164 /* The following preserves the byte order. */ 8165 data[i] = LE2HOST32(temp32); 8166 8167 i++; 8168 } 8169 8170 return (SOC_E_NONE); 8171 8172 } 8173 8174 int 8175 _axi_read_test(int unit,int port, uint32 reg) 8176 { 8177 phy_ctrl_t *pc; 8178 uint32 temp32; 8179 int rv; 8180 8181 pc = EXT_PHY_SW_STATE(unit, port); 8182 rv = _phy_8806x_axi_read(unit, pc, reg, &temp32, 1); 8183 8184 LOG_CLI((BSL_META_U(unit, 8185 "_sbus_read_test: u=%d p=%d " 8186 "value=0x%08x\n"), unit, pc->port, temp32)); 8187 return rv; 8188 } 8189 8190 int 8191 _axi_read_test2(int unit,int port, uint32 reg) 8192 { 8193 phy_ctrl_t *pc; 8194 uint32 temp32[2]; 8195 int rv; 8196 8197 pc = EXT_PHY_SW_STATE(unit, port); 8198 rv = _phy_8806x_axi_read(unit, pc, reg, temp32, 2); 8199 8200 LOG_CLI((BSL_META_U(unit, 8201 "_sbus_read_test: u=%d p=%d " 8202 "temp32[0]=0x%08x temp32[1]=0x%08x\n"), unit, pc->port, temp32[0], temp32[1])); 8203 return rv; 8204 } 8205 8206 int 8207 phy_is_8806x(phy_ctrl_t *pc) 8208 { 8209 return (PHY_IS_BCM8806X(pc) ? SOC_E_NONE : SOC_E_FAIL); 8210 } 8211 8212 int 8213 phy_8806x_fw_stat_read(int unit, int port, int offset, uint32 result[], int result_size) 8214 { 8215 phy_ctrl_t *pc; 8216 int rv = SOC_E_NONE; 8217 8218 pc = EXT_PHY_SW_STATE(unit, port); 8219 8220 if (sal_mutex_take(xmod_mutex[unit], XMOD_MUTEX_TIMEOUT) < 0) 8221 { 8222 LOG_WARN(BSL_LS_SOC_PHY, 8223 (BSL_META_U(unit, 8224 "phy_8806x_fw_stat_read: Couldn't aquire lock. u=%d p=%d\n"), \ 8225 unit, pc->port)); 8226 return SOC_E_FAIL; 8227 } 8228 8229 /* 0x{2,3,4,5}4 0200 : axi_buf = 0x240200 + (pc->phy_id & 0x3) * 0x100000 */ 8230 rv = _phy_8806x_axi_read(unit, pc, 0x240200 + ((pc->phy_id & 0x3) * 0x100000)+(offset*4), result, result_size); 8231 8232 sal_mutex_give(xmod_mutex[unit]); 8233 return rv; 8234 } 8235 8236 STATIC int 8237 _phy_8806x_xmod_command_send(int unit, phy_ctrl_t *pc, int mode_opcode, uint32 arg[], int arg_size) 8238 { 8239 uint16 status; 8240 int rv, ack_count = 0; 8241 8242 if ( FLAGS(pc) & PHY8806X_PM ) { 8243 return SOC_E_NONE; 8244 } 8245 8246 if (arg_size > 256) { 8247 LOG_WARN(BSL_LS_SOC_PHY, 8248 (BSL_META_U(unit, 8249 "PHY8806X command handler (invalid parameters): u=%d p=%d arg_size=%d\n"), \ 8250 unit, pc->port, arg_size)); 8251 return SOC_E_PARAM; 8252 } 8253 8254 retry_after_ack: 8255 soc_timeout_init(&TO(pc), 10000000, 0); /* 10000 ms timer */ 8256 8257 do { 8258 rv = READ_PHY8806X_FW_TO_SW_MESSAGE_REG(unit, pc, &status); 8259 if (!(status & (0x3 << 13)) || SOC_FAILURE(rv)) { 8260 break; 8261 } 8262 } while (!soc_timeout_check(&TO(pc))); 8263 if ((status & (0x3 << 13)) || SOC_FAILURE(rv)) { 8264 LOG_WARN(BSL_LS_SOC_PHY, 8265 (BSL_META_U(unit, 8266 "PHY8806X command handler timeout (not ready): u=%d p=%d status=0x%04x\n"), \ 8267 unit, pc->port, status)); 8268 _phy_8806x_xmod_command_ack(unit, pc); 8269 if (ack_count++ < RETRY_COUNT ) { 8270 goto retry_after_ack; 8271 } 8272 return SOC_E_TIMEOUT; 8273 } 8274 8275 /* 8276 -> 0x{2,3,4,5}4 0000 - 0x{2,3,4,5}4 00ff (256 bytes), axi_buf = 0x240000 + (pc->phy_id & 0x3) * 0x100000 8277 <- 0x{2,3,4,5}4 0100 - 0x{2,3,4,5}4 01ff (256 bytes), axi_buf = 0x240100 + (pc->phy_id & 0x3) * 0x100000 8278 */ 8279 8280 /* write arguments */ 8281 rv = _phy_8806x_axi_write(unit, pc, 0x240000 + (pc->phy_id & 0x3) * 0x100000, arg, arg_size); 8282 8283 if (SOC_FAILURE(rv)) { 8284 LOG_WARN(BSL_LS_SOC_PHY, 8285 (BSL_META_U(unit, 8286 "PHY8806X command handler (AXI write failure): u=%d p=%d\n"), \ 8287 unit, pc->port)); 8288 return SOC_E_FAIL; 8289 } 8290 8291 /* issue command */ 8292 rv = WRITE_PHY8806X_SW_TO_FW_INTERRUPT_REG(unit, pc, (1U << 15) | (mode_opcode & 0x7fff)); 8293 8294 if (SOC_FAILURE(rv)) { 8295 LOG_WARN(BSL_LS_SOC_PHY, 8296 (BSL_META_U(unit, 8297 "PHY8806X command handler (command failure): u=%d p=%d\n"), \ 8298 unit, pc->port)); 8299 return SOC_E_FAIL; 8300 } 8301 8302 soc_timeout_init(&TO(pc), 10000000, 0); /* 10000 ms timer */ 8303 8304 return SOC_E_NONE; 8305 } 8306 8307 8308 STATIC int 8309 _phy_8806x_xmod_result_recv(int unit, phy_ctrl_t *pc, uint32 result[], int result_size) 8310 { 8311 uint16 status; 8312 int rv, rval; 8313 8314 if ( FLAGS(pc) & PHY8806X_PM ) { 8315 return SOC_E_NONE; 8316 } 8317 8318 if (result_size > 256) { 8319 LOG_WARN(BSL_LS_SOC_PHY, 8320 (BSL_META_U(unit, 8321 "_phy_8806x_xmod_result_recv: invalid parameters: u=%d p=%d result_size=%d\n"), \ 8322 unit, pc->port, result_size)); 8323 /* issue ack command */ 8324 _phy_8806x_xmod_command_ack(unit, pc); 8325 return SOC_E_PARAM; 8326 } 8327 8328 do { 8329 rv = READ_PHY8806X_FW_TO_SW_MESSAGE_REG(unit, pc, &status); 8330 if ((status & (0x1 << 15)) | ((status & (0x3 << 13)) == (0x2 << 13)) || SOC_FAILURE(rv)) { 8331 break; 8332 } 8333 } while (!soc_timeout_check(&TO(pc))); 8334 8335 if (SOC_FAILURE(rv)) { 8336 LOG_WARN(BSL_LS_SOC_PHY, 8337 (BSL_META_U(unit, 8338 "PHY8806X command handler (status read failure): u=%d p=%d\n"), \ 8339 unit, pc->port)); 8340 /* issue ack command */ 8341 _phy_8806x_xmod_command_ack(unit, pc); 8342 return SOC_E_FAIL; 8343 } 8344 8345 if (status & (0x1 << 15)) { /* error */ 8346 LOG_WARN(BSL_LS_SOC_PHY, 8347 (BSL_META_U(unit, 8348 "PHY8806X command handler failure: u=%d p=%d status=0x%04x\n"), \ 8349 unit, pc->port, status)); 8350 /* issue ack command */ 8351 _phy_8806x_xmod_command_ack(unit, pc); 8352 rval = -(status & BFCMAP_ERROR_CODE_MASK); 8353 /* could err Code map before */ 8354 return rval; 8355 } 8356 8357 if ((status & (0x3 << 13)) != (0x2 << 13)) { /* result not ready */ 8358 LOG_WARN(BSL_LS_SOC_PHY, 8359 (BSL_META_U(unit, 8360 "PHY8806X command handler timeout (no result): u=%d p=%d status=0x%04x\n"), \ 8361 unit, pc->port, status)); 8362 /* issue ack command */ 8363 _phy_8806x_xmod_command_ack(unit, pc); 8364 return SOC_E_TIMEOUT; 8365 } 8366 8367 8368 /* 8369 -> 0x{2,3,4,5}4 0000 - 0x{2,3,4,5}4 00ff (256 bytes), axi_buf = 0x240000 + (pc->phy_id & 0x3) * 0x100000 8370 <- 0x{2,3,4,5}4 0100 - 0x{2,3,4,5}4 01ff (256 bytes), axi_buf = 0x240100 + (pc->phy_id & 0x3) * 0x100000 8371 */ 8372 8373 8374 /* read results */ 8375 rv = _phy_8806x_axi_read(unit, pc, 0x240100 + (pc->phy_id & 0x3) * 0x100000, result, result_size); 8376 8377 if (SOC_FAILURE(rv)) { 8378 LOG_WARN(BSL_LS_SOC_PHY, 8379 (BSL_META_U(unit, 8380 "PHY8806X command handler (AXI read failure): u=%d p=%d\n"), \ 8381 unit, pc->port)); 8382 /* issue ack command */ 8383 _phy_8806x_xmod_command_ack(unit, pc); 8384 8385 return SOC_E_FAIL; 8386 } 8387 8388 /* issue ack command */ 8389 _phy_8806x_xmod_command_ack(unit, pc); 8390 8391 return SOC_E_NONE; 8392 8393 } 8394 8395 int 8396 phy_8806x_xmod_command(int unit, int port, int mode_opcode, uint32 arg[], int arg_size, uint32 result[], int result_size) 8397 { 8398 phy_ctrl_t *pc; 8399 int rv; 8400 8401 pc = EXT_PHY_SW_STATE(unit, port); 8402 8403 /* MT2 XMOD set opcodes have the LSB set */ 8404 if ((SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)) && (mode_opcode & 0x1)) { 8405 return SOC_E_NONE; 8406 } 8407 8408 if (sal_mutex_take(xmod_mutex[unit], XMOD_MUTEX_TIMEOUT) < 0) 8409 { 8410 LOG_WARN(BSL_LS_SOC_PHY, 8411 (BSL_META_U(unit, 8412 "phy_8806x_xmod_command: Couldn't aquire lock. u=%d p=%d mode:0x%x cmd:0x%x \n"), \ 8413 unit, pc->port, (mode_opcode >> 8), (mode_opcode & 0xFF))); 8414 return SOC_E_FAIL; 8415 } 8416 8417 rv = _phy_8806x_xmod_command_send(unit, pc, mode_opcode, arg, arg_size); 8418 8419 if (SOC_FAILURE(rv)) { 8420 LOG_WARN(BSL_LS_SOC_PHY, 8421 (BSL_META_U(unit, 8422 "phy_8806x_xmod_command: send command failed. u=%d p=%d mode:0x%x cmd:0x%x \n"), \ 8423 unit, pc->port, (mode_opcode >> 8), (mode_opcode & 0xFF))); 8424 sal_mutex_give(xmod_mutex[unit]); 8425 return SOC_E_FAIL; 8426 } 8427 8428 rv = _phy_8806x_xmod_result_recv(unit, pc, result, result_size); 8429 8430 if (SOC_FAILURE(rv)) { 8431 LOG_WARN(BSL_LS_SOC_PHY, 8432 (BSL_META_U(unit, 8433 "phy_8806x_xmod_command: receive result failed. u=%d p=%d mode:0x%x cmd:0x%x \n"), \ 8434 unit, pc->port, (mode_opcode >> 8), (mode_opcode & 0xFF))); 8435 sal_mutex_give(xmod_mutex[unit]); 8436 return rv; 8437 } 8438 8439 sal_mutex_give(xmod_mutex[unit]); 8440 return SOC_E_NONE; 8441 } 8442 8443 STATIC int 8444 _phy_8806x_xmod_command_ack(int unit, phy_ctrl_t *pc) 8445 { 8446 int rv; 8447 8448 if ( FLAGS(pc) & PHY8806X_PM ) { 8449 return SOC_E_NONE; 8450 } 8451 8452 /* issue ack command */ 8453 rv = WRITE_PHY8806X_SW_TO_FW_INTERRUPT_REG(unit, pc, (1U << 15) | (0x17 & 0x7ff)); 8454 8455 if (SOC_FAILURE(rv)) { 8456 LOG_WARN(BSL_LS_SOC_PHY, 8457 (BSL_META_U(unit, 8458 "PHY8806X command handler (ack failure): u=%d p=%d\n"), \ 8459 unit, pc->port)); 8460 return SOC_E_FAIL; 8461 } 8462 8463 return SOC_E_NONE; 8464 } 8465 8466 8467 int xmod_test(int unit, int port) 8468 { 8469 uint32 temp32[2]; 8470 int rv; 8471 8472 temp32[0] = 0xaaaaaaaa; 8473 8474 rv = phy_8806x_xmod_command(unit, port, 0x12, &temp32[0], 1, &temp32[1], 1); 8475 8476 LOG_CLI((BSL_META_U(unit, 8477 "_phy_8806x_xmod_command: u=%d p=%d " 8478 "temp32[0]=0x%08x temp32[1]=0x%08x\n"), unit, port, temp32[0], temp32[1])); 8479 return rv; 8480 8481 8482 } 8483 8484 STATIC int _tsc_reg_read(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 *value) 8485 { 8486 uint32 data[4], mem_cmd; 8487 int ring; 8488 8489 ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */ 8490 8491 /* No other SBUS accesses between the write and the read. Ie. R5s need to be shutdown. */ 8492 8493 mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG << 26) |((((tsc_port > 8) ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7); 8494 8495 reg &= 0xffff; 8496 8497 data[0] = ( (reg | (pmd ? (1U << 27) : 0) ) | ( (tsc_port & 0x1f) << 19) ) | ((mode & 0x7) << 16) | (pll << 24); 8498 data[1] = 0; 8499 data[2] = 0; 8500 data[3] = 0; 8501 SOC_IF_ERROR_RETURN 8502 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 8503 8504 mem_cmd = (SBUS_READ_MEMORY_CMD_MSG << 26) |((((tsc_port > 8) ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7); 8505 8506 SOC_IF_ERROR_RETURN 8507 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 8508 8509 LOG_INFO(BSL_LS_SOC_PHY, (BSL_META_U(unit, 8510 "tsc_reg_read: u=%d p=%d tsc_port=%d" 8511 " data[0]=0x%08x data[1]=0x%08x data[2]=0x%08x data[3]=0x%08x\n"), 8512 unit, pc->port, tsc_port, data[0], data[1], data[2], data[3])); 8513 8514 *value = (data[1] & 0xffff); 8515 8516 return SOC_E_NONE; 8517 8518 } 8519 8520 int tsc_reg_read_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg) 8521 { 8522 phy_ctrl_t *pc; 8523 uint16 value; 8524 int tsc_port; 8525 8526 pc = EXT_PHY_SW_STATE(unit, port); 8527 8528 tsc_port = (sys << 3) + (((pc->phy_id & 0x4) ? 1 : 0) << 2) + 1; 8529 8530 SOC_IF_ERROR_RETURN 8531 (_tsc_reg_read(unit, pc, 0, tsc_port, pmd, pll, reg, &value)); 8532 8533 LOG_CLI((BSL_META_U(unit, 8534 "tsc_reg_read_test_base: u=%d p=%d %s " 8535 "reg=0x%04x value=0x%04x\n"), unit, port, sys ? "S":"L", reg, value)); 8536 8537 return SOC_E_NONE; 8538 } 8539 8540 8541 STATIC int _tsc_reg_write(int unit, phy_ctrl_t *pc, int mode, int tsc_port, int pmd, int pll, uint32 reg, uint16 value, uint16 mask) 8542 { 8543 uint32 data[4], mem_cmd; 8544 int ring; 8545 8546 ring = (pc->phy_id & 0x4) ? 1 : 0; /* mig too */ 8547 8548 mem_cmd = (SBUS_WRITE_MEMORY_CMD_MSG << 26) |((((tsc_port > 8) ? 0x7 : 0x3) & 0x7f) << 19) |(16 << 7); 8549 8550 reg &= 0xffff; 8551 8552 data[0] = ( (reg | (pmd ? (1U << 27) : 0) ) | ( (tsc_port & 0x1f) << 19) ) | ((mode & 0x7) << 16) | (pll << 24); 8553 data[1] = ((value & 0xffff) << 16) | (mask & 0xffff); 8554 data[2] = 1; 8555 data[3] = 0; 8556 8557 LOG_INFO(BSL_LS_SOC_PHY, (BSL_META_U(unit, 8558 "tsc_reg_write: u=%d p=%d tsc_port=%d" 8559 " data[0]=0x%08x data[1]=0x%08x data[2]=0x%08x data[3]=0x%08x\n"), 8560 unit, pc->port, tsc_port, data[0], data[1], data[2], data[3])); 8561 8562 SOC_IF_ERROR_RETURN 8563 (phy_8806x_sbus_cmd(unit, pc, 0x00000000, mem_cmd, ring, data)); 8564 8565 return SOC_E_NONE; 8566 8567 } 8568 8569 int tsc_reg_write_test_base(int unit, int port, int sys, int pmd, int pll, uint32 reg, uint16 value, uint16 mask) 8570 { 8571 phy_ctrl_t *pc; 8572 int tsc_port; 8573 8574 pc = EXT_PHY_SW_STATE(unit, port); 8575 8576 tsc_port = (sys << 3) + (((pc->phy_id & 0x4) ? 1 : 0) << 2) + 1; 8577 8578 SOC_IF_ERROR_RETURN 8579 (_tsc_reg_write(unit, pc, 0, tsc_port, pmd, pll, reg, value, mask)); 8580 8581 LOG_CLI((BSL_META_U(unit, 8582 "tsc_reg_write_test_base: u=%d p=%d %s " 8583 "reg=0x%04x value=0x%04x\n"), unit, port, sys ? "S":"L", reg, value)); 8584 8585 return SOC_E_NONE; 8586 } 8587 8588 STATIC int 8589 phy8806x_medium_get(int unit, soc_port_t port, soc_port_medium_t *medium) 8590 { 8591 if (medium == NULL) { 8592 return SOC_E_PARAM; 8593 } 8594 8595 *medium = SOC_PORT_MEDIUM_FIBER; 8596 8597 return SOC_E_NONE; 8598 } 8599 8600 8601 STATIC int 8602 phy8806x_medium_config_get(int unit, soc_port_t port, 8603 soc_port_medium_t medium, 8604 soc_phy_config_t *cfg) 8605 { 8606 int rv; 8607 phy_ctrl_t *pc; 8608 8609 pc = EXT_PHY_SW_STATE(unit, port); 8610 rv = SOC_E_NONE; 8611 8612 switch (medium) { 8613 case SOC_PORT_MEDIUM_FIBER: 8614 sal_memcpy(cfg, &pc->fiber, sizeof (*cfg)); 8615 break; 8616 default: 8617 rv = SOC_E_PARAM; 8618 break; 8619 } 8620 8621 return rv; 8622 } 8623 8624 8625 STATIC int _phy8806x_dump_buffer(int unit, int port, unsigned char *arg) 8626 { 8627 uint32 uart_ptr = 0, print_ptr = 0, temp32, uart_ptr_r = 0, print_ptr_r = 0, mode = 0; 8628 int cur_buf_size_r = 0, cur_buf_size = 0, avail_buf_size = 0, rv = SOC_E_NONE; 8629 phy_ctrl_t *pc = NULL; 8630 unsigned char *ch; 8631 8632 pc = EXT_PHY_SW_STATE(unit, port); 8633 8634 if (pc == NULL) { 8635 return SOC_E_FAIL; 8636 } 8637 ch = arg - 4; 8638 8639 avail_buf_size = (ch[0] | (ch[1] << 8) | (ch[2] << 16) | (ch[3] << 24)) - 8; /* 8 for rounding the AXI buffer */ 8640 8641 if (avail_buf_size < 0) { 8642 LOG_WARN(BSL_LS_SOC_PHY, 8643 (BSL_META_U(unit, 8644 "Insufficient UART buffer u=%d p=%d\n"), \ 8645 unit, pc->port)); 8646 return SOC_E_FAIL; 8647 } 8648 8649 if (sal_mutex_take(xmod_mutex[unit], XMOD_MUTEX_TIMEOUT) < 0) 8650 { 8651 LOG_WARN(BSL_LS_SOC_PHY, 8652 (BSL_META_U(unit, 8653 "phy_8806x_fw_stat_read: Couldn't aquire lock. u=%d p=%d\n"), \ 8654 unit, pc->port)); 8655 return SOC_E_FAIL; 8656 } 8657 8658 if (SOC_SUCCESS(rv)) { 8659 /* read the mode (uart_silent_mode) from the AXI memory of the mHost (pc->phy_id & 0x3) */ 8660 rv = _phy_8806x_axi_read(unit, pc, 0x27fff4 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1); 8661 mode = LE2HOST32(temp32) & 0x3; 8662 } 8663 8664 if (! mode ) { 8665 /* Real uart is active in f/w. Let it fall through. */ 8666 rv = SOC_E_FAIL; 8667 } 8668 8669 8670 if (SOC_SUCCESS(rv)) { 8671 /* read uart_ptr from the AXI memory of the mHost (pc->phy_id & 0x3) */ 8672 rv = _phy_8806x_axi_read(unit, pc, 0x27fff8 + (pc->phy_id & 0x3) * 0x100000, &temp32, 1); 8673 uart_ptr = LE2HOST32(temp32); 8674 } 8675 8676 if (SOC_SUCCESS(rv)) { 8677 /* read print_ptr from the AXI memory of the mHost (pc->phy_id & 0x3) */ 8678 rv = _phy_8806x_axi_read(unit, pc, 0x27fffc + (pc->phy_id & 0x3) * 0x100000, &temp32, 1); 8679 print_ptr = LE2HOST32(temp32); 8680 } 8681 8682 /* printf("Port %d mode = %d uart ptr 0x%x print ptr 0x%x\n", port, mode, uart_ptr, print_ptr); */ 8683 cur_buf_size = print_ptr - uart_ptr; 8684 8685 if ((cur_buf_size > 0) && (cur_buf_size > avail_buf_size)) { 8686 print_ptr -= cur_buf_size - avail_buf_size; 8687 } 8688 8689 if ((cur_buf_size < 0) && ( (0x8000 - 0x10 + cur_buf_size) > avail_buf_size)) { 8690 int temp; 8691 8692 temp = print_ptr - (0x8000 - 0x10 + cur_buf_size - avail_buf_size); 8693 if (temp < 0) { 8694 temp += 0x8000 - 0x10; 8695 } 8696 print_ptr = temp; 8697 } 8698 8699 if (SOC_SUCCESS(rv)) { 8700 uart_ptr_r = uart_ptr & ~0x3; /* uart_ptr rounded to the previous 4 byte boundary */ 8701 print_ptr_r = (print_ptr + 3) & ~0x3; /* print_ptr rounded to the next 4 byte boundary */ 8702 cur_buf_size_r = (print_ptr_r - uart_ptr_r); /* rounded cur_buf_size */ 8703 } 8704 8705 if (cur_buf_size_r > 0) { 8706 8707 if (SOC_SUCCESS(rv)) { 8708 rv = _phy_8806x_axi_read(unit, pc, 0x278000 + uart_ptr_r + ((pc->phy_id & 0x3) << 20), (uint32 *)arg, cur_buf_size_r >> 2 ); /* << 20 = * 0x100000 */ 8709 arg[cur_buf_size_r] = 0; 8710 } 8711 } else if (cur_buf_size_r < 0) { 8712 8713 if (SOC_SUCCESS(rv)) { 8714 /* Read from uart_ptr to end */ 8715 rv = _phy_8806x_axi_read(unit, pc, 0x278000 + uart_ptr_r + ((pc->phy_id & 0x3) << 20), (uint32 *)arg, ((0x8000 - 0x10 - uart_ptr_r) >> 2)); 8716 } 8717 8718 if (SOC_SUCCESS(rv)) { 8719 /* Read from start to print_ptr */ 8720 rv = _phy_8806x_axi_read(unit, pc, 0x278000 + ((pc->phy_id & 0x3) << 20), (uint32 *)(arg + 0x8000 - 0x10 - uart_ptr_r), print_ptr_r >> 2); 8721 } 8722 8723 arg[0x8000 - 0x10 + cur_buf_size_r] = 0; 8724 } else { 8725 arg[0] = 0; 8726 } 8727 8728 if (SOC_SUCCESS(rv)) { 8729 /* Write the print_prt value to the uart_prt localtion. */ 8730 temp32 = HOST2LE32(print_ptr); 8731 rv = _phy_8806x_axi_write(unit, pc, 0x27fff8 + ((pc->phy_id & 0x3) << 20), &temp32, 1); 8732 } 8733 8734 #if 0 8735 /* Read back values */ 8736 _phy_8806x_axi_read(unit, pc, 0x27fff8 + ((pc->phy_id & 0x3) << 20), &temp32, 1); 8737 uart_ptr = LE2HOST32(temp32); 8738 8739 _phy_8806x_axi_read(unit, pc, 0x27fffc + ((pc->phy_id & 0x3) << 20), &temp32, 1); 8740 print_ptr = LE2HOST32(temp32); 8741 8742 printf("After write Port %d uart ptr 0x%x print ptr 0x%x\n", port, uart_ptr, print_ptr); 8743 #endif 8744 8745 sal_mutex_give(xmod_mutex[unit]); 8746 8747 if (SOC_FAILURE(rv)) { 8748 arg[0] = 0; 8749 } 8750 return rv; 8751 } 8752 8753 int phy8806x_xmod_debug_cmd(int unit, int port) 8754 { 8755 phy_ctrl_t *pc; 8756 soc_phymod_phy_t *phy; 8757 soc_phymod_ctrl_t *pmc; 8758 int rv = SOC_E_NONE; 8759 8760 /* locate phy control */ 8761 pc = EXT_PHY_SW_STATE(unit, port); 8762 if (pc == NULL) { 8763 return SOC_E_INTERNAL; 8764 } 8765 8766 #if defined(INCLUDE_FCMAP) 8767 if (pc->fcmap_enable) { 8768 return SOC_E_UNAVAIL; 8769 } 8770 #endif 8771 8772 pmc = &pc->phymod_ctrl; 8773 phy = pmc->phy[0]; 8774 8775 rv = phymod_debug_ether(&phy->pm_phy); 8776 8777 return rv; 8778 } 8779 8780 STATIC uint32 8781 _phy8806x_speed_led_encode(int speed) 8782 { 8783 if (speed == 0) { 8784 return 0; 8785 } else if (speed == 1000000) { /* 1G */ 8786 return 0x1; 8787 } else if (speed == 10000000) { /* 10G */ 8788 return 0x2; 8789 } else if (speed == 20000000) { /* 20G */ 8790 return 0x3; 8791 } else if (speed == 25000000) { /* 25G */ 8792 return 0x4; 8793 } else if (speed == 40000000) { /* 40G */ 8794 return 0x5; 8795 } else if (speed == 50000000) { /* 50G */ 8796 return 0x6; 8797 } else if (speed == 100000000) { /* 100G */ 8798 return 0x7; 8799 } else if (speed == 4000000) { /* 4G - FC Only */ 8800 return 0x8; 8801 } else if (speed == 8000000) { /* 8G - FC Only */ 8802 return 0x9; 8803 } else if (speed == 16000000) { /* 16G - FC Only */ 8804 return 0xa; 8805 } else if (speed == 32000000) { /* 32G - FC Only */ 8806 return 0xb; 8807 } else { 8808 return 0xf; 8809 } 8810 } 8811 8812 int 8813 phy_mt2_update_led_speed_activity(int unit, soc_port_t port) 8814 { 8815 uint32 speed, portdata = 0; 8816 #ifdef BCM_TOMAHAWK_SUPPORT 8817 int byte; 8818 uint32 prev_data, led_dram_base; 8819 int phy_port = 0; /* physical port number */ 8820 soc_info_t *si = &SOC_INFO(unit); 8821 #endif /* BCM_TOMAHAWK_SUPPORT */ 8822 phy_ctrl_t *pc = EXT_PHY_SW_STATE(unit, port); 8823 8824 if ((pc == NULL) || (!PHY_IS_BCM8806X(pc))){ 8825 return SOC_E_NONE; 8826 } 8827 8828 /* Update TX activity */ 8829 if (LED_TX(pc)) { 8830 portdata |= 0x2; 8831 } 8832 /* Update RX activity */ 8833 if (LED_RX(pc)) { 8834 portdata |= 0x4; 8835 } 8836 /*Update Speed */ 8837 speed = _phy8806x_speed_led_encode(LED_SPEED(pc)); 8838 portdata |= (speed << 3); 8839 8840 /* For now, only implemented for Tomohawk. Expand as needed */ 8841 #ifdef BCM_TOMAHAWK_SUPPORT 8842 if (SOC_IS_TOMAHAWK(unit)) { 8843 phy_port = si->port_l2p_mapping[port]; 8844 led_dram_base = CMIC_LEDUP0_DATA_RAM_OFFSET; 8845 /* Tomahawk: Port 1-32 and 97-128 are in ledproc0 8846 * Port 33-96 are in ledproc1 8847 * Port 129 & 131 are in ledproc2 8848 */ 8849 if (phy_port > 32 && phy_port < 97) { 8850 led_dram_base = CMIC_LEDUP1_DATA_RAM_OFFSET; 8851 phy_port -= 32; 8852 } else if (phy_port == 129 ) { 8853 led_dram_base = CMIC_LEDUP2_DATA_RAM_OFFSET; 8854 phy_port = 1; 8855 } else if (phy_port == 131 ) { 8856 led_dram_base = CMIC_LEDUP2_DATA_RAM_OFFSET; 8857 phy_port = 2; 8858 } else if (phy_port > 32) { 8859 phy_port -= 64; 8860 } 8861 byte = LS_LED_DATA_OFFSET_A0 + phy_port - 1; 8862 8863 prev_data = soc_pci_read(unit, led_dram_base + CMIC_LED_REG_SIZE * byte); 8864 prev_data &= ~0x7e; 8865 /* if link is down, mark activity as down 8866 as activity is not being updated ..*/ 8867 if (prev_data & 0x01) { 8868 portdata |= prev_data; 8869 } else { 8870 portdata = prev_data; 8871 } 8872 soc_pci_write(unit, led_dram_base + CMIC_LED_REG_SIZE * byte, portdata); 8873 8874 } 8875 #endif /* BCM_TOMAHAWK_SUPPORT */ 8876 8877 return SOC_E_NONE; 8878 } 8879 8880 8881 #if PHY8806X_DEBUG 8882 int phy8806x_dev_debug_cmd(int unit, int port, int cmd, void *txbuf, int txlen, int *rsp, void *rxbuf, int rxlen) 8883 { 8884 uint32_t xmodtxbuff[XMOD_BUFFER_MAX_LEN/4]; 8885 uint32_t xmodrxbuff[XMOD_BUFFER_MAX_LEN/4]; 8886 uint8_t *buftxptr, *bufrxptr; 8887 int xmodtxlen, xmodrxlen; 8888 uint32_t x_cmd, x_response; 8889 int rv, tx_cmd_len, rx_cmd_len; 8890 8891 /* setting up xmod xmod_dev_debug_cmd: */ 8892 /* int xmod_dev_debug_cmd(IN uint32_t cmd, OUT uint32_t response); */ 8893 8894 tx_cmd_len = txlen + sizeof(x_cmd); 8895 rx_cmd_len = rxlen + sizeof(x_response); 8896 8897 /* check for tx lengths */ 8898 if (tx_cmd_len > XMOD_DEV_DEBUG_CMD_IN_LEN) { 8899 LOG_ERROR(BSL_LS_SOC_PHY, 8900 (BSL_META_U(unit, 8901 "ERROR, TX length (%d) too long > %d\n"), tx_cmd_len, XMOD_DEV_DEBUG_CMD_IN_LEN)); 8902 return SOC_E_PARAM; 8903 } 8904 /* check for rx lengths */ 8905 if (rx_cmd_len > XMOD_DEV_DEBUG_CMD_OUT_LEN) { 8906 LOG_ERROR(BSL_LS_SOC_PHY, 8907 (BSL_META_U(unit, 8908 "ERROR, RX length (%d) too long > %d\n"), rx_cmd_len, XMOD_DEV_DEBUG_CMD_OUT_LEN)); 8909 return SOC_E_PARAM; 8910 } 8911 8912 x_cmd = HOST2LE32(cmd); 8913 8914 /* write args to xmod buffer */ 8915 buftxptr = (uint8_t *)xmodtxbuff; 8916 WRITE_XMOD_ARG_BUFF(buftxptr, &x_cmd, sizeof(x_cmd)); 8917 xmodtxlen = sizeof(x_cmd); 8918 if ((txbuf!=NULL) && txlen) { 8919 WRITE_XMOD_ARG_BUFF(buftxptr, txbuf, txlen); 8920 xmodtxlen += txlen; 8921 } 8922 xmodtxlen = GET_XMOD_BUF_WORD_LEN(xmodtxlen); 8923 8924 /* get rx len */ 8925 xmodrxlen = sizeof(x_response); 8926 if ((rxbuf!=NULL) && rxlen) { 8927 xmodrxlen += rxlen; 8928 } 8929 xmodrxlen = GET_XMOD_BUF_WORD_LEN(xmodrxlen); 8930 8931 /* call xmod */ 8932 rv = phy_8806x_xmod_command(unit, port, XMOD_CMD_MODE_CORE(XMOD_DEV_DEBUG_CMD), xmodtxbuff, xmodtxlen, xmodrxbuff, xmodrxlen); 8933 8934 /* retrieve the argument from the xmod rx buffer */ 8935 bufrxptr = (uint8_t *)xmodrxbuff; 8936 READ_XMOD_ARG_BUFF(bufrxptr, &x_response, sizeof(x_response)); 8937 if ((rxbuf!=NULL) && rxlen) { 8938 READ_XMOD_ARG_BUFF(bufrxptr, rxbuf, rxlen); 8939 } 8940 *rsp = LE2HOST32(x_response); 8941 8942 return rv; 8943 } 8944 #endif 8945 8946 /* 8947 * Variable: 8948 * phy8806x_drv 8949 * Purpose: 8950 * Phy Driver for BCM8806X PHYs. 8951 */ 8952 phy_driver_t phy_8806xdrv = { 8953 /* .drv_name = */ "BCM8806X PHYMOD PHY Driver", 8954 /* .pd_init = */ phy_8806x_init, 8955 /* .pd_reset = */ phy_null_reset, 8956 /* .pd_link_get = */ phy_8806x_link_get, 8957 /* .pd_enable_set = */ phy_8806x_enable_set, 8958 /* .pd_enable_get = */ phy_8806x_enable_get, 8959 /* .pd_duplex_set = */ phy_null_set, 8960 /* .pd_duplex_get = */ phy_8806x_duplex_get, 8961 /* .pd_speed_set = */ phy_8806x_speed_set, 8962 /* .pd_speed_get = */ phy_8806x_speed_get, 8963 /* .pd_master_set = */ phy_null_set, 8964 /* .pd_master_get = */ phy_null_zero_get, 8965 /* .pd_an_set = */ phy_8806x_an_set, 8966 /* .pd_an_get = */ phy_8806x_an_get, 8967 /* .pd_adv_local_set = */ NULL, /* Deprecated */ 8968 /* .pd_adv_local_get = */ NULL, /* Deprecated */ 8969 /* .pd_adv_remote_get = */ NULL, /* Deprecated */ 8970 /* .pd_lb_set = */ phy_8806x_lb_set, 8971 /* .pd_lb_get = */ phy_8806x_lb_get, 8972 /* .pd_interface_set = */ phy_8806x_interface_set, 8973 /* .pd_interface_get = */ phy_8806x_interface_get, 8974 /* .pd_ability = */ NULL, /* Deprecated */ 8975 /* .pd_linkup_evt = */ phy_8806x_linkup, 8976 /* .pd_linkdn_evt = */ NULL, 8977 /* .pd_mdix_set = */ phy_null_mdix_set, 8978 /* .pd_mdix_get = */ phy_null_mdix_get, 8979 /* .pd_mdix_status_get = */ phy_null_mdix_status_get, 8980 /* .pd_medium_config_set = */ NULL, 8981 /* .pd_medium_config_get = */ phy8806x_medium_config_get, 8982 /* .pd_medium_get = */ phy8806x_medium_get, 8983 /* .pd_cable_diag = */ NULL, 8984 /* .pd_link_change = */ NULL, 8985 /* .pd_control_set = */ phy_8806x_control_set, 8986 /* .pd_control_get = */ phy_8806x_control_get, 8987 /* .pd_reg_read = */ phy_8806x_reg_read, 8988 /* .pd_reg_write = */ phy_8806x_reg_write, 8989 /* .pd_reg_modify = */ phy_8806x_reg_modify, 8990 /* .pd_notify = */ NULL, 8991 /* .pd_probe = */ phy_8806x_probe, 8992 /* .pd_ability_advert_set = */ phy_8806x_ability_advert_set, 8993 /* .pd_ability_advert_get = */ phy_8806x_ability_advert_get, 8994 /* .pd_ability_remote_get = */ phy_8806x_ability_remote_get, 8995 /* .pd_ability_local_get = */ phy_8806x_ability_local_get, 8996 /* .pd_firmware_set = */ phy_8806x_firmware_set, 8997 /* .pd_timesync_config_set = */ NULL, 8998 /* .pd_timesync_config_get = */ NULL, 8999 /* .pd_timesync_control_set = */ NULL, 9000 /* .pd_timesync_control_set = */ NULL, 9001 /* .pd_diag_ctrl = */ phy_8806x_diag_ctrl, 9002 /* .pd_lane_control_set = */ NULL, 9003 /* .pd_lane_control_get = */ NULL, 9004 /* .pd_lane_reg_read = */ NULL, 9005 /* .pd_lane_reg_write = */ NULL, 9006 /* .pd_oam_config_set = */ NULL, 9007 /* .pd_oam_config_get = */ NULL, 9008 /* .pd_oam_control_set = */ NULL, 9009 /* .pd_oam_control_get = */ NULL, 9010 /* .pd_timesync_enhanced_capture_get = */ NULL, 9011 /* .pd_multi_get = */ phy_8806x_multi_reg_read, 9012 /* .pd_precondition_before_probe = */ NULL, 9013 /* .pd_linkfault_get = */ phy_8806x_linkfault_get 9014 }; 9015 9016 #else 9017 int _8806x_not_empty; 9018 #endif /* INCLUDE_PHY_8806X */ 9019