pm8x50.c (365250B)
1 /* 2 * 3 * 4 * 5 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 6 * 7 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 8 */ 9 10 #include <soc/types.h> 11 #include <soc/error.h> 12 #include <soc/drv.h> 13 #include <soc/wb_engine.h> 14 #include <soc/portmod/portmod_internal.h> 15 #include <soc/portmod/portmod.h> 16 #include <soc/portmod/portmod_dispatch.h> 17 #include <soc/portmod/portmod_chain.h> 18 #include <soc/portmod/portmod_common.h> 19 #include <soc/portmod/portmod_defs.h> 20 #include <soc/mcm/memregs.h> 21 #include <soc/portmod/portmod_legacy_phy.h> 22 23 #ifdef _ERR_MSG_MODULE_NAME 24 #error "_ERR_MSG_MODULE_NAME redefined" 25 #endif 26 #define _ERR_MSG_MODULE_NAME BSL_LS_SOC_PORT 27 28 #ifdef PORTMOD_PM8X50_SUPPORT 29 30 #include <soc/portmod/cdmac.h> 31 #include <soc/portmod/pm8x50.h> 32 #include <soc/portmod/pm8x50_shared.h> 33 #include <soc/portmod/pm8x50_private.h> 34 #include <soc/portmod/pm8x50_internal.h> 35 36 #define PM_8x50_INFO(pm_info) ((pm_info)->pm_data.pm8x50_db) 37 38 /* Warmboot variable defines - start */ 39 40 #define PM8x50_WB_BUFFER_VERSION (4) 41 #define PORTMOD_THREAD_INTERVAL_1s 1000000 42 #define TIMEOUT_COUNT_400G_AN 10 43 44 #define PM8x50_IS_CORE_INITIALIZED_SET(unit, pm_info, is_core_initialized) \ 45 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 46 pm_info->wb_vars_ids[isCoreInitialized], \ 47 &is_core_initialized) 48 #define PM8x50_IS_CORE_INITIALIZED_GET(unit, pm_info, is_core_initialized) \ 49 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 50 pm_info->wb_vars_ids[isCoreInitialized], \ 51 is_core_initialized) 52 53 #define PM8x50_IS_ACTIVE_SET(unit, pm_info, is_active) \ 54 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 55 pm_info->wb_vars_ids[isActive],\ 56 &is_active) 57 #define PM8x50_IS_ACTIVE_GET(unit, pm_info, is_active) \ 58 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 59 pm_info->wb_vars_ids[isActive],\ 60 is_active) 61 62 #define PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, ovco_pll_active_lane_bitmap)\ 63 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 64 pm_info->wb_vars_ids[ovcopllActiveLaneBitmap], \ 65 &ovco_pll_active_lane_bitmap) 66 #define PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, ovco_pll_active_lane_bitmap)\ 67 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 68 pm_info->wb_vars_ids[ovcopllActiveLaneBitmap], \ 69 ovco_pll_active_lane_bitmap) 70 71 #define PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, tvco_pll_active_lane_bitmap)\ 72 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 73 pm_info->wb_vars_ids[tvcopllActiveLaneBitmap], \ 74 &tvco_pll_active_lane_bitmap) 75 #define PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, tvco_pll_active_lane_bitmap)\ 76 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 77 pm_info->wb_vars_ids[tvcopllActiveLaneBitmap], \ 78 tvco_pll_active_lane_bitmap) 79 80 #define PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, ovco_pll_adv_lane_bitmap)\ 81 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 82 pm_info->wb_vars_ids[ovcopllAdvLaneBitmap], \ 83 &ovco_pll_adv_lane_bitmap) 84 #define PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, ovco_pll_adv_lane_bitmap)\ 85 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 86 pm_info->wb_vars_ids[ovcopllAdvLaneBitmap], \ 87 ovco_pll_adv_lane_bitmap) 88 89 #define PM8x50_TVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, tvco_pll_adv_lane_bitmap)\ 90 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 91 pm_info->wb_vars_ids[tvcopllAdvLaneBitmap], \ 92 &tvco_pll_adv_lane_bitmap) 93 #define PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, tvco_pll_adv_lane_bitmap)\ 94 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 95 pm_info->wb_vars_ids[tvcopllAdvLaneBitmap], \ 96 tvco_pll_adv_lane_bitmap) 97 98 #define PM8x50_LANE2PORT_SET(unit, pm_info, lane, port) \ 99 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 100 pm_info->wb_vars_ids[lane2portMap], &port, lane) 101 #define PM8x50_LANE2PORT_GET(unit, pm_info, lane, port) \ 102 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 103 pm_info->wb_vars_ids[lane2portMap], port, lane) 104 105 #define PM8x50_MAX_SPEED_SET(unit, pm_info, max_speed, port_index) \ 106 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 107 pm_info->wb_vars_ids[maxSpeed], &max_speed, port_index) 108 #define PM8x50_MAX_SPEED_GET(unit, pm_info, max_speed, port_index) \ 109 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 110 pm_info->wb_vars_ids[maxSpeed], max_speed, port_index) 111 112 #define PM8x50_AN_MODE_SET(unit, pm_info, an_mode, port_index) \ 113 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 114 pm_info->wb_vars_ids[anMode], &an_mode, port_index) 115 #define PM8x50_AN_MODE_GET(unit, pm_info, an_mode, port_index) \ 116 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 117 pm_info->wb_vars_ids[anMode], an_mode, port_index) 118 119 #define PM8x50_LANE2FEC_SET(unit, pm_info, lane, fec) \ 120 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 121 pm_info->wb_vars_ids[lane2fecMap], &fec, lane) 122 #define PM8x50_LANE2FEC_GET(unit, pm_info, lane, fec) \ 123 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 124 pm_info->wb_vars_ids[lane2fecMap], fec, lane) 125 126 #define PM8x50_PORT_IS_PCS_BYPASSED_SET(unit, pm_info, is_bypassed, port_index) \ 127 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 128 pm_info->wb_vars_ids[portIsPcsBypassed], &is_bypassed, port_index) 129 #define PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, is_bypassed, port_index) \ 130 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 131 pm_info->wb_vars_ids[portIsPcsBypassed], is_bypassed, port_index) 132 133 #define PM8x50_TS_ENABLE_PORT_COUNT_SET(unit, pm_info, ts_enable_port_count) \ 134 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 135 pm_info->wb_vars_ids[tsEnablePortCount],\ 136 &ts_enable_port_count) 137 #define PM8x50_TS_ENABLE_PORT_COUNT_GET(unit, pm_info, ts_enable_port_count) \ 138 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 139 pm_info->wb_vars_ids[tsEnablePortCount],\ 140 ts_enable_port_count) 141 142 #define PM8x50_TIMESYNC_ENABLE_SET(unit, pm_info, timesync_enable, port_index) \ 143 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 144 pm_info->wb_vars_ids[timesyncEnable], ×ync_enable, port_index) 145 #define PM8x50_TIMESYNC_ENABLE_GET(unit, pm_info, timesync_enable, port_index) \ 146 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 147 pm_info->wb_vars_ids[timesyncEnable], timesync_enable, port_index) 148 149 #define PM8x50_RLM_ENABLE_SET(unit, pm_info, rlmEnabled, port_index) \ 150 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 151 pm_info->wb_vars_ids[rlmEnable], &rlmEnabled, port_index) 152 #define PM8x50_RLM_ENABLE_GET(unit, pm_info, rlmEnabled, port_index) \ 153 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 154 pm_info->wb_vars_ids[rlmEnable], rlmEnabled, port_index) 155 156 #define PM8x50_INITIATOR_SET(unit, pm_info, is_initiator, port_index) \ 157 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 158 pm_info->wb_vars_ids[initiator], &is_initiator, port_index) 159 #define PM8x50_INITIATOR_GET(unit, pm_info, is_initiator, port_index) \ 160 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 161 pm_info->wb_vars_ids[initiator], is_initiator, port_index) 162 163 #define PM8x50_PCS_RECONFIG_SET(unit, pm_info, pcs_reconfig, port_index) \ 164 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 165 pm_info->wb_vars_ids[pcsReconfigured], &pcs_reconfig, port_index) 166 #define PM8x50_PCS_RECONFIG_GET(unit, pm_info, pcs_reconfig, port_index) \ 167 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 168 pm_info->wb_vars_ids[pcsReconfigured], pcs_reconfig, port_index) 169 170 #define PM8x50_ACTIVE_LANE_MAP_SET(unit, pm_info, active_lane_map, port_index) \ 171 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 172 pm_info->wb_vars_ids[activeLaneBitMap], &active_lane_map, port_index) 173 #define PM8x50_ACTIVE_LANE_MAP_GET(unit, pm_info, active_lane_map, port_index) \ 174 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 175 pm_info->wb_vars_ids[activeLaneBitMap], active_lane_map, port_index) 176 177 #define PM8x50_RLM_STATE_SET(unit, pm_info, rlm_state, port_index) \ 178 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 179 pm_info->wb_vars_ids[rlmState], &rlm_state, port_index) 180 #define PM8x50_RLM_STATE_GET(unit, pm_info, rlm_state, port_index) \ 181 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 182 pm_info->wb_vars_ids[rlmState], rlm_state, port_index) 183 184 #define PM8x50_ORIGINAL_FEC_SET(unit, pm_info, orig_fec, port_index) \ 185 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 186 pm_info->wb_vars_ids[originalFec], &orig_fec, port_index) 187 #define PM8x50_ORIGINAL_FEC_GET(unit, pm_info, orig_fec, port_index) \ 188 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 189 pm_info->wb_vars_ids[originalFec], orig_fec, port_index) 190 191 #define PM8x50_ORIG_TX_LANE_MAP_SET(unit, pm_info, tx_lane_map)\ 192 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 193 pm_info->wb_vars_ids[originalTxLaneSwap], \ 194 &tx_lane_map) 195 #define PM8x50_ORIG_TX_LANE_MAP_GET(unit, pm_info, tx_lane_map)\ 196 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 197 pm_info->wb_vars_ids[originalTxLaneSwap], \ 198 tx_lane_map) 199 200 #define PM8x50_ORIG_RX_LANE_MAP_SET(unit, pm_info, rx_lane_map)\ 201 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 202 pm_info->wb_vars_ids[originalRxLaneSwap], \ 203 &rx_lane_map) 204 #define PM8x50_ORIG_RX_LANE_MAP_GET(unit, pm_info, rx_lane_map)\ 205 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 206 pm_info->wb_vars_ids[originalRxLaneSwap], \ 207 rx_lane_map) 208 209 #define PM8x50_400G_AN_ENABLE_SET(unit, pm_info, is_400g_an, port_index) \ 210 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 211 pm_info->wb_vars_ids[is400gAn], &is_400g_an, port_index) 212 #define PM8x50_400G_AN_ENABLE_GET(unit, pm_info, is_400g_an, port_index) \ 213 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 214 pm_info->wb_vars_ids[is400gAn], is_400g_an, port_index) 215 216 #define PM8x50_400G_AN_STATE_SET(unit, pm_info, an_state_400g) \ 217 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 218 pm_info->wb_vars_ids[anState400g],\ 219 &an_state_400g) 220 #define PM8x50_400G_AN_STATE_GET(unit, pm_info, an_state_400g) \ 221 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 222 pm_info->wb_vars_ids[anState400g],\ 223 an_state_400g) 224 225 #define PM8x50_400G_AN_WAIT_LINK_COUNT_SET(unit, pm_info, an_wait_link_count) \ 226 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 227 pm_info->wb_vars_ids[anWaitlinkCount],\ 228 &an_wait_link_count) 229 #define PM8x50_400G_AN_WAIT_LINK_COUNT_GET(unit, pm_info, an_wait_link_count) \ 230 SOC_WB_ENGINE_GET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 231 pm_info->wb_vars_ids[anWaitlinkCount],\ 232 an_wait_link_count) 233 234 #define PM8x50_BER_WAR_ENABLE_SET(unit, pm_info, is_ber_war_enable, port_index) \ 235 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 236 pm_info->wb_vars_ids[isBerWarEnable], &is_ber_war_enable, port_index) 237 238 #define PM8x50_BER_WAR_STATE_SET(unit, pm_info, ber_war_state, port_index) \ 239 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 240 pm_info->wb_vars_ids[berWarState], &ber_war_state, port_index) 241 242 #define PM8x50_BER_WAR_WAIT_COUNT_SET(unit, pm_info, ber_war_wait_count, port_index) \ 243 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 244 pm_info->wb_vars_ids[berWarWaitCount], &ber_war_wait_count, port_index) 245 246 #define PM8x50_IS_CORE_FLEXE_CONFIGURED_SET(unit, pm_info, is_core_flexe_configured) \ 247 SOC_WB_ENGINE_SET_VAR(unit, SOC_WB_ENGINE_PORTMOD, \ 248 pm_info->wb_vars_ids[coreisFlexeConfigured], \ 249 &is_core_flexe_configured) 250 251 #define PM8x50_400G_AN_REMOTE_PAUSE_SET(unit, pm_info, an_400g_remote_pause, port_index) \ 252 SOC_WB_ENGINE_SET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 253 pm_info->wb_vars_ids[an400gRemotePause], &an_400g_remote_pause, port_index) 254 #define PM8x50_400G_AN_REMOTE_PAUSE_GET(unit, pm_info, an_400g_remote_pause, port_index) \ 255 SOC_WB_ENGINE_GET_ARR(unit, SOC_WB_ENGINE_PORTMOD, \ 256 pm_info->wb_vars_ids[an400gRemotePause], an_400g_remote_pause, port_index) 257 258 typedef enum pm8x50_wb_vars{ 259 isCoreInitialized, 260 isActive, 261 isBypassed, /* Removed */ 262 ovcopllActiveLaneBitmap, 263 tvcopllActiveLaneBitmap, 264 ovcopllAdvLaneBitmap, 265 tvcopllAdvLaneBitmap, 266 lane2portMap, 267 maxSpeed, 268 anMode, 269 anFec, /* Removed */ 270 fsCl72, /* Removed */ 271 lane2fecMap, 272 tsEnablePortCount, 273 timesyncEnable, 274 rlmEnable, /* for RLM */ 275 initiator, /* for RLM */ 276 pcsReconfigured, /* for RLM */ 277 activeLaneBitMap, /* for RLM */ 278 rlmState, /* for RLM */ 279 originalFec, /* for RLM */ 280 originalTxLaneSwap, /* for RLM */ 281 originalRxLaneSwap, /* for RLM */ 282 is400gAn, /* 400g An enabled */ 283 anState400g, /* 400G an state */ 284 anWaitlinkCount, /* 400G wait for link up count */ 285 portIsPcsBypassed, 286 isBerWarEnable, /* Currently not supported */ 287 berWarState, /* Currently not supported */ 288 berWarWaitCount, /* Currently not supported */ 289 coreisFlexeConfigured, /* Currently not supported */ 290 an400gRemotePause, /* 400G AN Remote PAUSE value */ 291 }pm8x50_wb_vars_t; 292 293 typedef enum pm8x50_port_soft_reset_mode{ 294 PM8X50_PORT_SOFT_RESET_MODE_IN_OUT = 0, 295 PM8X50_PORT_SOFT_RESET_MODE_IN = 1, 296 PM8X50_PORT_SOFT_RESET_MODE_OUT = 2 297 }pm8x50_port_soft_reset_mode_t; 298 299 /* Warmboot variable defines - end */ 300 301 /* This macro set devad to reg_addr if it is PMD phy address. */ 302 #define PM8X50_PHY_REG_SET(reg_addr) \ 303 do { \ 304 uint32 phy_reg_addr; \ 305 phy_reg_addr = reg_addr & 0xffff; \ 306 if ((0x90 <= phy_reg_addr && phy_reg_addr <= 0x9f) || \ 307 (0xd000 <= phy_reg_addr && phy_reg_addr <= 0xd4ff) || \ 308 (0xffd0 <= phy_reg_addr && phy_reg_addr <= 0xffdf)) { \ 309 reg_addr |= 1 << 16; \ 310 } \ 311 } while (0) 312 313 #define PM8X50_MAX_NUM_PLLS (2) 314 315 #define PM8X50_TVCO_PLL_INDEX_GET(pm_info) PM_8x50_INFO(pm_info)->int_core_access.access.tvco_pll_index 316 317 #define PM8x50_VCO_ALL (PM8x50_VCO_ILKN_20P625G | PM8x50_VCO_ETH_20P625G | PM8x50_VCO_ILKN_25G | PM8x50_VCO_ETH_25G | PM8x50_VCO_ETH_25P781G | PM8x50_VCO_ILKN_25P781G | PM8x50_VCO_ETH_26P562G | PM8x50_VCO_ILKN_26P562G | PM8x50_VCO_ILKN_27P343G | PM8x50_VCO_ILKN_28P125G) 318 319 #define PM8x50_VCO_BMP_EMPTY(bmp) \ 320 ( (bmp & PM8x50_VCO_ALL) == 0 ) 321 322 #define PM8x50_VCO_BMP_20P625G_ETH_ONLY(bmp) \ 323 ( (bmp == PM8x50_VCO_ETH_20P625G) || (bmp == (PM8x50_VCO_ETH_20P625G | PM8x50_VCO_ILKN_20P625G)) ) 324 325 #define PM8x50_VCO_BMP_25G_ETH_ONLY(bmp) \ 326 ((bmp == PM8x50_VCO_ETH_25G) || (bmp == (PM8x50_VCO_ETH_25G | PM8x50_VCO_ILKN_25G))) 327 328 /* VCO is dedicated for bypassed ports */ 329 #define PORTMOD_VCO_PCS_BYPASS_DEDICATED(vco) \ 330 ((vco == portmodVCO28P125G) || (vco == portmodVCO27P343G) || (vco == portmodVCO25G)) 331 332 /* Highest NRZ per lane speed is 28.125G, supported in ILKN mode */ 333 #define NRZ_MAX_PER_LANE_SPEED 28125 334 335 #define PM8x50_FS_ABILITY_TABLE_SIZE 29 336 #define PM8x50_AN_ABILITY_TABLE_SIZE 34 337 #define PM8x50_MAX_AN_ABILITY 20 338 339 #define FLEXPORT_SW_WAR_ENABLE 0x1000 340 341 /* following defines are used for 400G AN SW WAR */ 342 #define AN_X4_SW_CTRL_STS_REG 0xc1e6 343 #define AN_X4_SW_CTRL_STS_AN_COMPLETE_MASK 0x8000 344 #define AN_X4_CL73_CFG_REG 0xc1c0 345 #define AN_X4_CL73_CFG_AN_DISABLE_MASK 0xfaff 346 #define MAIN0_SETUP_REG 0x9000 347 #define MAIN0_SETUP_PORT_MODE_CLEAR 0xff8f 348 #define MAIN0_SETUP_PORT_MODE_OCTAL 0x50 349 #define SPEED_CTRL_REG 0xc050 350 #define SPEED_CTRL_SPEED_ID_CLEAR 0xffc0 351 #define SPEED_ID_400G 0xa 352 353 #define AN_X4_LP_BASE1r_REG 0xc1d3 354 #define AN_LP_BASE1r_PAGE_PAUSE_MASK 0x3 355 #define AN_LP_BASE1r_PAGE_PAUSE_OFFSET 0xA 356 357 STATIC portmod_ucode_buf_t pm8x50_ucode_buf[SOC_MAX_NUM_DEVICES] = {{NULL, 0}}; 358 STATIC portmod_ucode_buf_t pm8x50_ucode_buf_2nd[SOC_MAX_NUM_DEVICES] = {{NULL, 0}}; 359 360 typedef enum pm8x50_port_400g_an_state_e { 361 PM8X50_PORT_AN_CHECK_PAGE_COMPLETE, 362 PM8X50_PORT_AN_CHECK_PCS_LINKUP, 363 PM8X50_PORT_AN_CREDIT_RESET, 364 PM8X50_PORT_AN_DISABLE, 365 PM8X50_PORT_AN_RESTART, 366 PM8X50_PORT_AN_COMPLETE, 367 PM8X50_PORT_AN_STATE_COUNT 368 } pm8x50_port_400g_an_state_t; 369 370 /* 371 * 200G and 400G BER monitoring workaround state 372 */ 373 typedef enum pm8x50_port_ber_war_state_e { 374 PM8X50_PORT_BER_WAR_STATE_COUNT = 4 375 } pm8x50_port_ber_war_state_t; 376 377 /* 378 * Entries of the force speed ability table; each entry specifies a 379 * unique FS port speed ability and its associated VCO rate 380 */ 381 typedef struct pm8x50_fs_ability_table_entry_s { 382 uint32 speed; /* port speed in Mbps */ 383 uint32 num_lanes; /* number of lanes */ 384 portmod_fec_t fec_type; /* FEC type */ 385 portmod_vco_type_t vco; /* associated VCO rate of the ability */ 386 } pm8x50_fs_ability_table_entry_t; 387 388 /* 389 * Entries of the autoneg ability table; each entry specifies a unique 390 * AN speed ability and its associated VCO rate 391 */ 392 typedef struct pm8x50_an_ability_table_entry_s { 393 uint32 speed; /* port speed in Mbps */ 394 uint32 num_lanes; /* number of lanes */ 395 portmod_fec_t fec_type; /* FEC type */ 396 portmod_port_phy_control_autoneg_mode_t an_mode; /* autoneg mode such as cl73, bam or msa */ 397 portmod_vco_type_t vco; /* associated VCO rate of the ability */ 398 } pm8x50_an_ability_table_entry_t; 399 400 typedef enum cdmac_port_mode_e{ 401 CDMAC_4_LANES_SEPARATE = 0, 402 CDMAC_3_TRI_0_1_2_2 = 1, 403 CDMAC_3_TRI_0_0_2_3 = 2, 404 CDMAC_2_LANES_DUAL = 3, 405 CDMAC_4_LANES_TOGETHER = 4 406 } cdmac_port_mode_t; 407 408 #define CDMAC_NUM_LANES 4 409 /* 410 * Defines: 411 * portmod_port_rlm_fsm_t * 412 * Purpose: 413 * Valid values Reduced Lane Mode state 414 */ 415 typedef enum portmod_port_rlm_fsm_e { 416 PORTMOD_PORT_RLM_SEND_PACKET_DATA, /*entry state for RLM */ 417 PORTMOD_PORT_RLM_STOP_MAC, /* STALL TX */ 418 PORTMOD_PORT_RLM_SEND_LI, /* SEND link interrupt protocol */ 419 PORTMOD_PORT_RLM_SEND_PRBS, /* SEND prbs data */ 420 PORTMOD_PORT_RLM_SEND_IDLE, /* send idle */ 421 PORTMOD_PORT_RLM_DONE, /* RLM transition done */ 422 PORTMOD_PORT_RLM_ERROR, /* RLM error state */ 423 PORTMOD_PORT_RLM_FSM_COUNT 424 } portmod_port_rlm_fsm_t; 425 426 /* 427 * Defines: 428 * portmod_port_rlm_state_t * 429 * Purpose: 430 * pm8x50 RLM data structure 431 */ 432 typedef struct portmod_port_rlm_state_s { 433 portmod_port_rlm_fsm_t rlm_state; 434 } portmod_port_rlm_state_t; 435 436 437 /* a comprehensive list of pm8x50 forced speed abilities and their VCO rates */ 438 const pm8x50_fs_ability_table_entry_t pm8x50_fs_ability_table[PM8x50_FS_ABILITY_TABLE_SIZE] = 439 { 440 /* port_speed, num_lanes, fec_type, vco */ 441 {10000, 1, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO20P625G}, 442 {10000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, portmodVCO20P625G}, 443 {12000, 1, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO25G }, 444 {20000, 1, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO20P625G}, 445 {20000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, portmodVCO20P625G}, 446 {40000, 4, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO20P625G}, 447 {40000, 4, PORTMOD_PORT_PHY_FEC_BASE_R, portmodVCO20P625G}, 448 {40000, 2, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO20P625G}, 449 {25000, 1, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO25P781G}, 450 {25000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, portmodVCO25P781G}, 451 {25000, 1, PORTMOD_PORT_PHY_FEC_RS_FEC, portmodVCO25P781G}, 452 {50000, 1, PORTMOD_PORT_PHY_FEC_RS_FEC, portmodVCO25P781G}, 453 {50000, 2, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO25P781G}, 454 {50000, 2, PORTMOD_PORT_PHY_FEC_RS_FEC, portmodVCO25P781G}, 455 {100000, 2, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO25P781G}, 456 {100000, 2, PORTMOD_PORT_PHY_FEC_RS_FEC, portmodVCO25P781G}, 457 {100000, 4, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO25P781G}, 458 {100000, 4, PORTMOD_PORT_PHY_FEC_RS_FEC, portmodVCO25P781G}, 459 {200000, 4, PORTMOD_PORT_PHY_FEC_NONE, portmodVCO25P781G}, 460 {50000, 1, PORTMOD_PORT_PHY_FEC_RS_544, portmodVCO26P562G}, 461 {50000, 1, PORTMOD_PORT_PHY_FEC_RS_272, portmodVCO26P562G}, 462 {50000, 2, PORTMOD_PORT_PHY_FEC_RS_544, portmodVCO26P562G}, 463 {100000, 2, PORTMOD_PORT_PHY_FEC_RS_544, portmodVCO26P562G}, 464 {100000, 2, PORTMOD_PORT_PHY_FEC_RS_272, portmodVCO26P562G}, 465 {100000, 4, PORTMOD_PORT_PHY_FEC_RS_544, portmodVCO26P562G}, 466 {200000, 4, PORTMOD_PORT_PHY_FEC_RS_272, portmodVCO26P562G}, 467 {200000, 4, PORTMOD_PORT_PHY_FEC_RS_544, portmodVCO26P562G}, 468 {200000, 4, PORTMOD_PORT_PHY_FEC_RS_544_2XN, portmodVCO26P562G}, 469 {400000, 8, PORTMOD_PORT_PHY_FEC_RS_544_2XN, portmodVCO26P562G} 470 }; 471 472 /* a comprehensive list of pm8x50 autoneg abilities and their VCO rates */ 473 const pm8x50_an_ability_table_entry_t pm8x50_an_ability_table[PM8x50_AN_ABILITY_TABLE_SIZE] = 474 { 475 /* port_speed, num_lanes, fec_type, autoneg_mode, vco */ 476 {10000, 1, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO20P625G}, 477 {10000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO20P625G}, 478 {20000, 1, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO20P625G}, 479 {20000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO20P625G}, 480 {40000, 2, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO20P625G}, 481 {40000, 4, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO20P625G}, 482 {40000, 4, PORTMOD_PORT_PHY_FEC_BASE_R, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO20P625G}, 483 {25000, 1, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO25P781G}, 484 {25000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO25P781G}, 485 {25000, 1, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO25P781G}, 486 {25000, 1, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA, portmodVCO25P781G}, 487 {25000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA, portmodVCO25P781G}, 488 {25000, 1, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA, portmodVCO25P781G}, 489 {25000, 1, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 490 {25000, 1, PORTMOD_PORT_PHY_FEC_BASE_R, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 491 {25000, 1, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 492 {50000, 1, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 493 {50000, 1, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 494 {50000, 2, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA, portmodVCO25P781G}, 495 {50000, 2, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA, portmodVCO25P781G}, 496 {50000, 2, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 497 {50000, 2, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 498 {100000, 2, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 499 {100000, 2, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 500 {100000, 4, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 501 {100000, 4, PORTMOD_PORT_PHY_FEC_RS_FEC, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO25P781G}, 502 {200000, 4, PORTMOD_PORT_PHY_FEC_NONE, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO25P781G}, 503 {50000, 1, PORTMOD_PORT_PHY_FEC_RS_544, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO26P562G}, 504 {50000, 2, PORTMOD_PORT_PHY_FEC_RS_544, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO26P562G}, 505 {100000, 2, PORTMOD_PORT_PHY_FEC_RS_544, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO26P562G}, 506 {100000, 4, PORTMOD_PORT_PHY_FEC_RS_544, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO26P562G}, 507 {200000, 4, PORTMOD_PORT_PHY_FEC_RS_544_2XN, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73 , portmodVCO26P562G}, 508 {200000, 4, PORTMOD_PORT_PHY_FEC_RS_544, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM, portmodVCO26P562G}, 509 {400000, 8, PORTMOD_PORT_PHY_FEC_RS_544_2XN, PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA, portmodVCO26P562G} 510 }; 511 512 static phymod_dispatch_type_t pm8x50_serdes_list[] = 513 { 514 phymodDispatchTypeTscbh, 515 phymodDispatchTypeInvalid 516 }; 517 518 /* 519 * given the port speed, number of lanes, and FEC type, return the VCO specified in 520 * pm8x50_fs_ability_table in the associated entry; VCO should be portmodVCOInvalid 521 * if the ability is invalid 522 */ 523 STATIC 524 int _pm8x50_fs_ability_table_vco_get(uint32 speed, uint32 num_lanes, portmod_fec_t fec_type, 525 portmod_vco_type_t* vco) 526 { 527 int i; 528 529 *vco = portmodVCOInvalid; 530 for (i = 0; i < PM8x50_FS_ABILITY_TABLE_SIZE; i++) { 531 if (pm8x50_fs_ability_table[i].speed == speed && 532 pm8x50_fs_ability_table[i].num_lanes == num_lanes && 533 pm8x50_fs_ability_table[i].fec_type == fec_type) 534 { 535 *vco = pm8x50_fs_ability_table[i].vco; 536 break; 537 } 538 } 539 540 return SOC_E_NONE; 541 } 542 543 /* 544 * given the port speed, number of lanes, FEC type, and autoneg mode, return the VCO specified in 545 * pm8x50_an_ability_table; VCO should be portmodVCOInvalid if the ability is invalid. 546 * this function is temporarily masked out because there is no caller. advert_ability_get() will 547 * need to call this function to verify the VCO requirement 548 */ 549 STATIC 550 int _pm8x50_an_ability_table_vco_get(uint32 speed, uint32 num_lanes, portmod_fec_t fec_type, 551 portmod_port_phy_control_autoneg_mode_t an_mode, 552 portmod_vco_type_t* vco) 553 { 554 int i; 555 556 *vco = portmodVCOInvalid; 557 for (i = 0; i < PM8x50_AN_ABILITY_TABLE_SIZE; i++) { 558 if (pm8x50_an_ability_table[i].speed == speed && 559 pm8x50_an_ability_table[i].num_lanes == num_lanes && 560 pm8x50_an_ability_table[i].fec_type == fec_type && 561 pm8x50_an_ability_table[i].an_mode == an_mode) 562 { 563 *vco = pm8x50_an_ability_table[i].vco; 564 break; 565 } 566 } 567 568 return SOC_E_NONE; 569 } 570 571 /* read an entry of pm8x50_fs_ability_table[] */ 572 STATIC 573 int _pm8x50_fs_ability_table_read_entry(int index, pm8x50_fs_ability_table_entry_t *table_entry) 574 { 575 SOC_INIT_FUNC_DEFS; 576 577 if (index < 0 || index >= PM8x50_FS_ABILITY_TABLE_SIZE) { 578 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, ("index to read in pm8x50_fs_ability_table is out of boundary")); 579 } 580 581 *table_entry = pm8x50_fs_ability_table[index]; 582 583 exit: 584 SOC_FUNC_RETURN; 585 } 586 587 /* read an entry of pm8x50_an_ability_table[] */ 588 STATIC 589 int _pm8x50_an_ability_table_read_entry(int index, pm8x50_an_ability_table_entry_t *table_entry) 590 { 591 SOC_INIT_FUNC_DEFS; 592 593 if (index < 0 || index >= PM8x50_AN_ABILITY_TABLE_SIZE) { 594 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, ("index to read in pm8x50_an_ability_table is out of boundary")); 595 } 596 597 *table_entry = pm8x50_an_ability_table[index]; 598 599 exit: 600 SOC_FUNC_RETURN; 601 } 602 603 STATIC 604 int _pm8x50_port_index_get(int unit, int port, pm_info_t pm_info, 605 int *first_index, uint32 *bitmap) 606 { 607 int i, rv = 0, tmp_port = 0; 608 609 SOC_INIT_FUNC_DEFS; 610 611 *first_index = -1; 612 *bitmap = 0; 613 614 for( i = 0 ; i < MAX_PORTS_PER_PM8X50; i++){ 615 rv = PM8x50_LANE2PORT_GET(unit, pm_info, i, &tmp_port); 616 _SOC_IF_ERR_EXIT(rv); 617 618 if(tmp_port == port){ 619 *first_index = (*first_index == -1 ? i : *first_index); 620 SHR_BITSET(bitmap, i); 621 } 622 } 623 624 if(*first_index == -1) { 625 _SOC_EXIT_WITH_ERR(SOC_E_INTERNAL, 626 (_SOC_MSG("port was not found in internal DB %d"), port)); 627 } 628 629 exit: 630 SOC_FUNC_RETURN; 631 } 632 633 STATIC int 634 _pm8x50_phy_access_get( 635 int unit, 636 int port, 637 pm_info_t pm_info, 638 int *phy_acc) 639 { 640 uint32 is_bypassed = 0; 641 int port_index; 642 uint32 bitmap[1]; 643 644 SOC_INIT_FUNC_DEFS; 645 646 *phy_acc = 0; 647 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, bitmap)); 648 _SOC_IF_ERR_EXIT(PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &is_bypassed, port_index)); 649 if (is_bypassed) { 650 *phy_acc = (PM_8x50_INFO(pm_info)->first_phy + port_index) | SOC_REG_ADDR_PHY_ACC_MASK; 651 } else { 652 *phy_acc = port; 653 } 654 655 exit: 656 SOC_FUNC_RETURN; 657 } 658 659 STATIC 660 int _pm8x50_port_interrupt_all_enable_set(int unit, int port, int enable) 661 { 662 int i = 0; 663 portmod_intr_type_t intrs[] = { 664 portmodIntrTypeMacErr, 665 portmodIntrTypeTscCore0Err, 666 portmodIntrTypeTscCore1Err, 667 portmodIntrTypeTxPktUnderflow, 668 portmodIntrTypeTxPktOverflow, 669 portmodIntrTypeTxCdcSingleBitErr, 670 portmodIntrTypeTxCdcDoubleBitErr, 671 portmodIntrTypeMibMemSingleBitErr, 672 portmodIntrTypeMibMemDoubleBitErr, 673 portmodIntrTypeMibMemMultipleBitErr 674 }; 675 SOC_INIT_FUNC_DEFS; 676 677 for (i = 0; i < sizeof(intrs)/sizeof(intrs[0]); i++) { 678 _SOC_IF_ERR_EXIT( 679 portmod_port_interrupt_enable_set(unit, port, intrs[i], enable)); 680 } 681 682 exit: 683 SOC_FUNC_RETURN; 684 } 685 686 STATIC 687 int _pm8x50_pm_port_mode_update(int unit, 688 int port, 689 pm_info_t pm_info, 690 int first_phy_index, 691 int num_lanes) 692 { 693 uint32 reg_val, mac_port_mode, mac_new_port_mode = 0, is_400g_port = 0; 694 int phy_acc, first_lane_local = 0, mac_stage_id = 0; 695 696 SOC_INIT_FUNC_DEFS; 697 698 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 699 700 mac_stage_id = first_phy_index / CDMAC_NUM_LANES; 701 first_lane_local = first_phy_index % CDMAC_NUM_LANES; 702 703 _SOC_IF_ERR_EXIT(READ_CDPORT_MODE_REGr(unit, phy_acc, ®_val)); 704 is_400g_port = soc_reg_field_get(unit, CDPORT_MODE_REGr, reg_val, SINGLE_PORT_MODE_SPEED_400Gf); 705 706 if (mac_stage_id) { 707 /* MAC1 need to update port mode */ 708 mac_port_mode = soc_reg_field_get(unit, CDPORT_MODE_REGr, reg_val, MAC1_PORT_MODEf); 709 } else { 710 /* MAC0 need to update port mode */ 711 mac_port_mode = soc_reg_field_get(unit, CDPORT_MODE_REGr, reg_val, MAC0_PORT_MODEf); 712 } 713 714 if (num_lanes == 8) { 715 /* 400G single port mode */ 716 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, SINGLE_PORT_MODE_SPEED_400Gf, 1); 717 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC1_PORT_MODEf, CDMAC_4_LANES_TOGETHER); 718 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC0_PORT_MODEf, CDMAC_4_LANES_TOGETHER); 719 } else if (num_lanes == 4) { 720 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, SINGLE_PORT_MODE_SPEED_400Gf, 0); 721 if (mac_stage_id) { 722 /* MAC1 is single-port mode */ 723 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC1_PORT_MODEf, CDMAC_4_LANES_TOGETHER); 724 } else { 725 /* MAC0 is single-port mode */ 726 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC0_PORT_MODEf, CDMAC_4_LANES_TOGETHER); 727 } 728 } else if (num_lanes == 2) { 729 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, SINGLE_PORT_MODE_SPEED_400Gf, 0); 730 switch (mac_port_mode) { 731 case CDMAC_4_LANES_SEPARATE: 732 if (first_lane_local == 0) { 733 mac_new_port_mode = CDMAC_3_TRI_0_0_2_3; 734 } else{ 735 mac_new_port_mode = CDMAC_3_TRI_0_1_2_2; 736 } 737 break; 738 case CDMAC_3_TRI_0_1_2_2: 739 if (first_lane_local == 0) { 740 mac_new_port_mode = CDMAC_2_LANES_DUAL; 741 } else { 742 mac_new_port_mode = CDMAC_3_TRI_0_1_2_2; 743 } 744 break; 745 case CDMAC_3_TRI_0_0_2_3: 746 if (first_lane_local == 0) { 747 mac_new_port_mode = CDMAC_3_TRI_0_0_2_3; 748 } else { 749 mac_new_port_mode = CDMAC_2_LANES_DUAL; 750 } 751 break; 752 case CDMAC_2_LANES_DUAL: 753 mac_new_port_mode = CDMAC_2_LANES_DUAL; 754 break; 755 case CDMAC_4_LANES_TOGETHER: 756 mac_new_port_mode = CDMAC_2_LANES_DUAL; 757 break; 758 default: 759 break; 760 } 761 if (mac_stage_id) { 762 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC1_PORT_MODEf, mac_new_port_mode); 763 } else { 764 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC0_PORT_MODEf, mac_new_port_mode); 765 } 766 } else if (num_lanes == 1) { 767 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, SINGLE_PORT_MODE_SPEED_400Gf, 0); 768 switch (mac_port_mode) { 769 case CDMAC_4_LANES_SEPARATE: 770 mac_new_port_mode = CDMAC_4_LANES_SEPARATE; 771 break; 772 case CDMAC_3_TRI_0_1_2_2: 773 if ((first_lane_local == 0) || (first_lane_local == 1)) { 774 mac_new_port_mode = CDMAC_3_TRI_0_1_2_2; 775 } else if ((first_lane_local == 2) || (first_lane_local == 3)) { 776 mac_new_port_mode = CDMAC_4_LANES_SEPARATE; 777 } 778 break; 779 case CDMAC_3_TRI_0_0_2_3: 780 if ((first_lane_local == 0) || (first_lane_local == 1)) { 781 mac_new_port_mode = CDMAC_4_LANES_SEPARATE; 782 } else if ((first_lane_local == 2) || (first_lane_local == 3)) { 783 mac_new_port_mode = CDMAC_3_TRI_0_0_2_3; 784 } 785 break; 786 case CDMAC_2_LANES_DUAL: 787 if ((first_lane_local == 0) || (first_lane_local == 1)) { 788 mac_new_port_mode = CDMAC_3_TRI_0_1_2_2; 789 } else if ((first_lane_local == 2) || (first_lane_local == 3)){ 790 mac_new_port_mode = CDMAC_3_TRI_0_0_2_3; 791 } 792 break; 793 case CDMAC_4_LANES_TOGETHER: 794 mac_new_port_mode = CDMAC_4_LANES_SEPARATE; 795 break; 796 default: 797 break; 798 } 799 if (mac_stage_id) { 800 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC1_PORT_MODEf, mac_new_port_mode); 801 } else { 802 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC0_PORT_MODEf, mac_new_port_mode); 803 /* if current port is 400G mode, need to write cdmac1 as well */ 804 if (is_400g_port) { 805 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC1_PORT_MODEf, mac_new_port_mode); 806 } 807 } 808 } 809 _SOC_IF_ERR_EXIT(WRITE_CDPORT_MODE_REGr(unit, phy_acc, reg_val)); 810 811 exit: 812 SOC_FUNC_RETURN; 813 814 } 815 816 817 STATIC 818 int _pm8x50_400g_an_workaround(int unit, int port, pm_info_t pm_info, int* is_done) 819 { 820 portmod_access_get_params_t params; 821 phymod_phy_access_t phy_access; 822 uint32_t serdes_reg_val, wait_link_count, base_reg_val, remote_pause; 823 int nof_phys; 824 pm8x50_port_400g_an_state_t an_state; 825 phymod_autoneg_control_t an_control; 826 char* state_string = "\n"; 827 int port_index; 828 uint32 bitmap; 829 830 SOC_INIT_FUNC_DEFS; 831 832 *is_done = 0; 833 834 /* first get the an state and wait link count */ 835 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_GET(unit, pm_info, &an_state)); 836 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_WAIT_LINK_COUNT_GET(unit, pm_info, &wait_link_count)); 837 838 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 839 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 840 ¶ms, 1, &phy_access, &nof_phys, NULL)); 841 842 /* based on the AN state */ 843 switch (an_state) { 844 case PM8X50_PORT_AN_CHECK_PAGE_COMPLETE: 845 { 846 state_string = "AN_CHECK_PAGE_COMPLETE\n"; 847 /* first read SW autoneg status register 0xc1e6 */ 848 /* clear the status first*/ 849 _SOC_IF_ERR_EXIT(phymod_phy_reg_read(&phy_access, AN_X4_SW_CTRL_STS_REG, &serdes_reg_val)); 850 sal_usleep(100); 851 _SOC_IF_ERR_EXIT(phymod_phy_reg_read(&phy_access, AN_X4_SW_CTRL_STS_REG, &serdes_reg_val)); 852 853 if (serdes_reg_val & AN_X4_SW_CTRL_STS_AN_COMPLETE_MASK) { 854 int phy_acc; 855 uint32 reg_val; 856 857 /* get port index */ 858 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 859 _SOC_IF_ERR_EXIT(phymod_phy_reg_read(&phy_access, AN_X4_LP_BASE1r_REG, &base_reg_val)); 860 /* store remote pause value */ 861 remote_pause = (base_reg_val >> AN_LP_BASE1r_PAGE_PAUSE_OFFSET) & AN_LP_BASE1r_PAGE_PAUSE_MASK; 862 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_REMOTE_PAUSE_SET(unit, pm_info, remote_pause, port_index)); 863 864 /* need to move one to the next stage */ 865 /* disable AN_Cl73 and AN_CL73BAM */ 866 _SOC_IF_ERR_EXIT(phymod_phy_reg_read(&phy_access, AN_X4_CL73_CFG_REG, &serdes_reg_val)); 867 serdes_reg_val &= AN_X4_CL73_CFG_AN_DISABLE_MASK; 868 _SOC_IF_ERR_EXIT(phymod_phy_reg_write(&phy_access, AN_X4_CL73_CFG_REG, serdes_reg_val)); 869 870 /* next disable rx/tx and set discard */ 871 _SOC_IF_ERR_EXIT(cdmac_rx_enable_set(unit, port, 0)); 872 _SOC_IF_ERR_EXIT(cdmac_discard_set(unit, port, 1)); 873 _SOC_IF_ERR_EXIT(cdmac_soft_reset_set(unit, port, 1)); 874 _SOC_IF_ERR_EXIT(cdmac_tx_enable_set(unit, port, 0)); 875 876 /* next update the cdport mode register */ 877 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 878 _SOC_IF_ERR_EXIT(READ_CDPORT_MODE_REGr(unit, phy_acc, ®_val)); 879 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, SINGLE_PORT_MODE_SPEED_400Gf, 1); 880 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC1_PORT_MODEf, CDMAC_4_LANES_TOGETHER); 881 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC0_PORT_MODEf, CDMAC_4_LANES_TOGETHER); 882 _SOC_IF_ERR_EXIT(WRITE_CDPORT_MODE_REGr(unit, phy_acc, reg_val)); 883 884 /* next update serdes side port mode to be octal */ 885 _SOC_IF_ERR_EXIT(phymod_phy_reg_read(&phy_access, MAIN0_SETUP_REG, &serdes_reg_val)); 886 serdes_reg_val = (serdes_reg_val & MAIN0_SETUP_PORT_MODE_CLEAR) | MAIN0_SETUP_PORT_MODE_OCTAL; 887 _SOC_IF_ERR_EXIT(phymod_phy_reg_write(&phy_access, MAIN0_SETUP_REG, serdes_reg_val)); 888 889 /* next assert pcs reset */ 890 _SOC_IF_ERR_EXIT(phymod_phy_pcs_enable_set(&phy_access, 0)); 891 /* change the speed id to use 0xa*/ 892 _SOC_IF_ERR_EXIT(phymod_phy_reg_read(&phy_access, SPEED_CTRL_REG, &serdes_reg_val)); 893 serdes_reg_val = (serdes_reg_val & SPEED_CTRL_SPEED_ID_CLEAR) | SPEED_ID_400G; 894 _SOC_IF_ERR_EXIT(phymod_phy_reg_write(&phy_access, SPEED_CTRL_REG, serdes_reg_val)); 895 /* release pcs reset */ 896 _SOC_IF_ERR_EXIT(phymod_phy_pcs_enable_set(&phy_access, 1)); 897 an_state = PM8X50_PORT_AN_CHECK_PCS_LINKUP; 898 } 899 break; 900 } 901 case PM8X50_PORT_AN_CHECK_PCS_LINKUP: 902 { 903 int link, phy_acc, remote_fault; 904 uint32 rval; 905 906 state_string = "AN_CHECK_PCS_LINKUP\n"; 907 /* first check link status */ 908 _SOC_IF_ERR_EXIT(phymod_phy_link_status_get(&phy_access, (uint32_t *)&link)); 909 _SOC_IF_ERR_EXIT(phymod_phy_link_status_get(&phy_access, (uint32_t *)&link)); 910 911 /* next check remote fualt */ 912 _SOC_IF_ERR_EXIT(cdmac_remote_fault_status_get(unit, port, &remote_fault)); 913 _SOC_IF_ERR_EXIT(cdmac_remote_fault_status_get(unit, port, &remote_fault)); 914 915 if (link && (!remote_fault)) { 916 /*re-enable tx/rx and disable DISCARD */ 917 _SOC_IF_ERR_EXIT(cdmac_discard_set(unit, port, 0)); 918 919 /* next re-enable CDMAC TX/RX */ 920 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 921 _SOC_IF_ERR_EXIT(READ_CDMAC_CTRLr(unit, phy_acc, &rval)); 922 soc_reg_field_set(unit, CDMAC_CTRLr, &rval, TX_ENf, TRUE); 923 soc_reg_field_set(unit, CDMAC_CTRLr, &rval, RX_ENf, TRUE); 924 soc_reg_field_set(unit, CDMAC_CTRLr, &rval, SW_LINK_STATUSf, TRUE); 925 _SOC_IF_ERR_EXIT(WRITE_CDMAC_CTRLr(unit, phy_acc, rval)); 926 wait_link_count = 0; 927 an_state = PM8X50_PORT_AN_CREDIT_RESET; 928 _SOC_IF_ERR_EXIT(cdmac_soft_reset_set(unit, port, 0)); 929 } else { 930 wait_link_count++; 931 /* next check if AN needs to restarted */ 932 if (wait_link_count > TIMEOUT_COUNT_400G_AN) { 933 an_state = PM8X50_PORT_AN_DISABLE; 934 wait_link_count = 0; 935 } 936 } 937 938 break; 939 } 940 case PM8X50_PORT_AN_DISABLE: 941 { 942 state_string = "AN_DISABLE \n"; 943 /* first needs to disable */ 944 an_control.enable = 0; 945 an_control.an_mode = phymod_AN_MODE_CL73_MSA; 946 an_control.num_lane_adv = 8; 947 _SOC_IF_ERR_EXIT(phymod_phy_autoneg_set(&phy_access, &an_control)); 948 an_state = PM8X50_PORT_AN_RESTART; 949 break; 950 } 951 case PM8X50_PORT_AN_RESTART: 952 { 953 state_string = "AN_RESTART \n"; 954 _SOC_IF_ERR_EXIT(_pm8x50_pm_port_mode_update(unit, port, pm_info, 0, 1)); 955 956 /* needs to enable autoneg */ 957 an_control.enable = 1; 958 an_control.an_mode = phymod_AN_MODE_CL73_MSA; 959 an_control.num_lane_adv = 8; 960 _SOC_IF_ERR_EXIT(phymod_phy_autoneg_set(&phy_access, &an_control)); 961 an_state = PM8X50_PORT_AN_CHECK_PAGE_COMPLETE; 962 break; 963 } 964 965 case PM8X50_PORT_AN_CREDIT_RESET: 966 { 967 int link, remote_fault; 968 state_string = "AN_CREDIT_RESET \n"; 969 970 /* first check if link is up, if not, need to re-start AN */ 971 _SOC_IF_ERR_EXIT(phymod_phy_link_status_get(&phy_access, (uint32_t *)&link)); 972 _SOC_IF_ERR_EXIT(phymod_phy_link_status_get(&phy_access, (uint32_t *)&link)); 973 974 /* next check remote fualt */ 975 _SOC_IF_ERR_EXIT(cdmac_remote_fault_status_get(unit, port, &remote_fault)); 976 _SOC_IF_ERR_EXIT(cdmac_remote_fault_status_get(unit, port, &remote_fault)); 977 978 if (link && (!remote_fault)) { 979 /* first assert MAC soft reset */ 980 _SOC_IF_ERR_EXIT(cdmac_soft_reset_set(unit, port, 1)); 981 /* Callback egress buffer reset function */ 982 if (PM_8x50_INFO(pm_info)->portmod_egress_buffer_reset) { 983 _SOC_IF_ERR_EXIT(PM_8x50_INFO(pm_info)->portmod_egress_buffer_reset(unit, port)); 984 } else { 985 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 986 (_SOC_MSG("The callback function is not defined \n"))); 987 } 988 989 /* de-assert CDMAC soft reset */ 990 _SOC_IF_ERR_EXIT(cdmac_soft_reset_set(unit, port, 0)); 991 992 an_state = PM8X50_PORT_AN_COMPLETE; 993 } else { 994 /*if no link or remote fault, re-start AN */ 995 an_state = PM8X50_PORT_AN_DISABLE; 996 wait_link_count = 0; 997 } 998 break; 999 } 1000 case PM8X50_PORT_AN_COMPLETE: 1001 { 1002 int link, remote_fault; 1003 state_string = "AN_COMPLETE \n"; 1004 1005 /* first check link status */ 1006 _SOC_IF_ERR_EXIT(phymod_phy_link_status_get(&phy_access, (uint32_t *)&link)); 1007 _SOC_IF_ERR_EXIT(phymod_phy_link_status_get(&phy_access, (uint32_t *) &link)); 1008 1009 /* next check remote fault */ 1010 _SOC_IF_ERR_EXIT(cdmac_remote_fault_status_get(unit, port, &remote_fault)); 1011 _SOC_IF_ERR_EXIT(cdmac_remote_fault_status_get(unit, port, &remote_fault)); 1012 1013 /* only if link up and no remote fault, declare AN complete */ 1014 if (link && (!remote_fault)) { 1015 state_string = "AN_COMPLETE \n"; 1016 *is_done = 1; 1017 } else { 1018 an_state = PM8X50_PORT_AN_DISABLE; 1019 wait_link_count = 0; 1020 *is_done = 0; 1021 } 1022 break; 1023 } 1024 default: 1025 *is_done = 1; 1026 break; 1027 } 1028 1029 LOG_VERBOSE(BSL_LS_SOC_PHY, 1030 (BSL_META_U(unit, 1031 "port %d 400G AN state is %-23s \n"), 1032 port, state_string)); 1033 1034 /* next store the an state */ 1035 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_SET(unit, pm_info, an_state)); 1036 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_WAIT_LINK_COUNT_SET(unit, pm_info, wait_link_count)); 1037 1038 exit: 1039 SOC_FUNC_RETURN; 1040 } 1041 1042 STATIC 1043 void _pm8x50_signalling_method_get(int is_bypassed, 1044 const portmod_speed_config_t *speed_config, 1045 phymod_phy_signalling_method_t *signalling_method) 1046 { 1047 int lane_rate; 1048 1049 if (!is_bypassed) { 1050 lane_rate = speed_config->speed / speed_config->num_lane; 1051 } else { 1052 lane_rate = speed_config->speed; 1053 } 1054 1055 *signalling_method = (lane_rate > NRZ_MAX_PER_LANE_SPEED ? phymodSignallingMethodPAM4 : phymodSignallingMethodNRZ); 1056 } 1057 1058 /* Convert the given VCO value to bitmap 1059 * 1060 * Inputs: 1061 * unit: unit number; 1062 * vco: vco value; 1063 * is_pcs_bypass: is port in PCS bypass mode; 1064 * required_vco_bmp: vco bitmap; 1065 * 1066 * Output: 1067 * non_bypassed_ports: Non-bypass ports bitmap 1068 */ 1069 1070 STATIC 1071 int _pm8x50_required_vco_bitmap_get( 1072 int unit, 1073 portmod_vco_type_t vco, 1074 int is_pcs_bypass, 1075 pm8x50_vcos_bmp_t *required_vco_bmp) 1076 { 1077 SOC_INIT_FUNC_DEFS; 1078 1079 *required_vco_bmp = 0; 1080 if (vco == portmodVCO20P625G && is_pcs_bypass) { 1081 PM8x50_VCO_ILKN_20P625G_SET(*required_vco_bmp); 1082 } else if (vco == portmodVCO20P625G && !is_pcs_bypass) { 1083 PM8x50_VCO_ETH_20P625G_SET(*required_vco_bmp); 1084 } else if (vco == portmodVCO25G && is_pcs_bypass) { 1085 PM8x50_VCO_ILKN_25G_SET(*required_vco_bmp); 1086 } else if (vco == portmodVCO25P781G && !is_pcs_bypass) { 1087 PM8x50_VCO_ETH_25P781G_SET(*required_vco_bmp); 1088 } else if (vco == portmodVCO25P781G && is_pcs_bypass) { 1089 PM8x50_VCO_ILKN_25P781G_SET(*required_vco_bmp); 1090 } else if (vco == portmodVCO26P562G && !is_pcs_bypass) { 1091 PM8x50_VCO_ETH_26P562G_SET(*required_vco_bmp); 1092 } else if (vco == portmodVCO26P562G && is_pcs_bypass) { 1093 PM8x50_VCO_ILKN_26P562G_SET(*required_vco_bmp); 1094 } else if (vco == portmodVCO27P343G && is_pcs_bypass) { 1095 PM8x50_VCO_ILKN_27P343G_SET(*required_vco_bmp); 1096 } else if (vco == portmodVCO28P125G && is_pcs_bypass) { 1097 PM8x50_VCO_ILKN_28P125G_SET(*required_vco_bmp); 1098 } else if (vco == portmodVCO25G && !is_pcs_bypass) { 1099 PM8x50_VCO_ETH_25G_SET(*required_vco_bmp); 1100 } else { 1101 _SOC_EXIT_WITH_ERR(SOC_E_UNAVAIL, (_SOC_MSG("Unsupport VCO value! \n"))); 1102 } 1103 exit: 1104 SOC_FUNC_RETURN; 1105 } 1106 1107 /* Iterate over VCO values from VCO bitmap: 1108 * - return the VCO value of highest rate. 1109 * - clear returned VCO rate. 1110 * 1111 * Inputs: 1112 * unit: unit number; 1113 * required_vcos: VCO bitmap; 1114 * vco: VCO rate; 1115 * is_pcs_bypass: is in PCS bypass mode 1116 * Output: 1117 * non_bypassed_ports: Non-bypass ports bitmap 1118 */ 1119 STATIC 1120 int _pm8x50_required_vco_value_iter( 1121 int unit, 1122 pm8x50_vcos_bmp_t *required_vcos, 1123 portmod_vco_type_t *vco, 1124 int *is_pcs_bypass) 1125 { 1126 SOC_INIT_FUNC_DEFS; 1127 1128 if (PM8x50_VCO_ILKN_28P125G_GET(*required_vcos)) { 1129 *vco = portmodVCO28P125G; 1130 *is_pcs_bypass = 1; 1131 PM8x50_VCO_ILKN_28P125G_CLR(*required_vcos); 1132 } else if (PM8x50_VCO_ILKN_27P343G_GET(*required_vcos)) { 1133 *vco = portmodVCO27P343G; 1134 *is_pcs_bypass = 1; 1135 PM8x50_VCO_ILKN_27P343G_CLR(*required_vcos); 1136 } else if (PM8x50_VCO_ETH_26P562G_GET(*required_vcos)) { 1137 *vco = portmodVCO26P562G; 1138 *is_pcs_bypass = 0; 1139 PM8x50_VCO_ETH_26P562G_CLR(*required_vcos); 1140 } else if (PM8x50_VCO_ILKN_26P562G_GET(*required_vcos)) { 1141 *vco = portmodVCO26P562G; 1142 *is_pcs_bypass = 1; 1143 PM8x50_VCO_ILKN_26P562G_CLR(*required_vcos); 1144 } else if (PM8x50_VCO_ETH_25P781G_GET(*required_vcos)) { 1145 *vco = portmodVCO25P781G; 1146 *is_pcs_bypass = 0; 1147 PM8x50_VCO_ETH_25P781G_CLR(*required_vcos); 1148 } else if (PM8x50_VCO_ILKN_25P781G_GET(*required_vcos)) { 1149 *vco = portmodVCO25P781G; 1150 *is_pcs_bypass = 1; 1151 PM8x50_VCO_ILKN_25P781G_CLR(*required_vcos); 1152 } else if (PM8x50_VCO_ILKN_25G_GET(*required_vcos)) { 1153 *vco = portmodVCO25G; 1154 *is_pcs_bypass = 1; 1155 PM8x50_VCO_ILKN_25G_CLR(*required_vcos); 1156 } else if (PM8x50_VCO_ETH_20P625G_GET(*required_vcos)) { 1157 *vco = portmodVCO20P625G; 1158 *is_pcs_bypass = 0; 1159 PM8x50_VCO_ETH_20P625G_CLR(*required_vcos); 1160 } else if (PM8x50_VCO_ILKN_20P625G_GET(*required_vcos)) { 1161 *vco = portmodVCO20P625G; 1162 *is_pcs_bypass = 1; 1163 PM8x50_VCO_ILKN_20P625G_CLR(*required_vcos); 1164 } else if (PM8x50_VCO_ETH_25G_GET(*required_vcos)) { 1165 /* 1166 * Ethernet 25G need to be served after Ethernet 20.625G. 1167 * Because TVCO can never run at 25G, while 20.625G could be 1168 * TVCO if requested by user. 1169 */ 1170 *vco = portmodVCO25G; 1171 *is_pcs_bypass = 0; 1172 PM8x50_VCO_ETH_25G_CLR(*required_vcos); 1173 } else { 1174 _SOC_EXIT_WITH_ERR(SOC_E_UNAVAIL, (_SOC_MSG("Unsupport VCO value! \n"))); 1175 } 1176 1177 exit: 1178 SOC_FUNC_RETURN; 1179 } 1180 1181 1182 1183 /* 1184 * Get PM active Ethernet port lanes bitmap. 1185 * 1186 * This API doesn't consider the ports whose speeds 1187 * are not configured. 1188 * 1189 * Inputs: 1190 * unit: unit number; 1191 * pm_info: pm_info data structure; 1192 * 1193 * Output: 1194 * eth_active_lanes: active ethernet lane bitmap 1195 */ 1196 1197 STATIC 1198 int _pm8x50_pm_active_eth_lanes_get(int unit, 1199 pm_info_t pm_info, 1200 uint8_t * eth_active_lanes) 1201 { 1202 int tmp_port, i, is_pcs_bypassed = 0; 1203 uint8_t ovco_pll_active_lane_bitmap, tvco_pll_active_lane_bitmap; 1204 uint8_t ovco_pll_adv_lane_bitmap, tvco_pll_adv_lane_bitmap; 1205 uint8_t all_active_lane_bitmap; 1206 1207 SOC_INIT_FUNC_DEFS; 1208 1209 _SOC_IF_ERR_EXIT( 1210 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_active_lane_bitmap)); 1211 _SOC_IF_ERR_EXIT( 1212 PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_active_lane_bitmap)); 1213 _SOC_IF_ERR_EXIT( 1214 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_adv_lane_bitmap)); 1215 _SOC_IF_ERR_EXIT( 1216 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_adv_lane_bitmap)); 1217 1218 all_active_lane_bitmap = (ovco_pll_active_lane_bitmap | tvco_pll_active_lane_bitmap | 1219 ovco_pll_adv_lane_bitmap | tvco_pll_adv_lane_bitmap); 1220 1221 *eth_active_lanes = 0; 1222 for(i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 1223 /* Exclude the ports whose speeds are not configured */ 1224 if (all_active_lane_bitmap & (1 << i)) { 1225 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info, i, &tmp_port)); 1226 if (tmp_port >= 0) { 1227 _SOC_IF_ERR_EXIT(PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &is_pcs_bypassed, i)); 1228 if (!is_pcs_bypassed) { 1229 *eth_active_lanes |= (1 << i); 1230 } 1231 } 1232 } 1233 } 1234 exit: 1235 SOC_FUNC_RETURN; 1236 } 1237 1238 1239 /* 1240 * Check if the VCO rate served as TVCO rate can drive Ethernet ports. 1241 * 1242 * This function will return 1 if the input VCO can drvie 1243 * Ethernet ports as TVCO rate. Otherwise, return 0. 1244 * 1245 * Inputs: 1246 * unit - Unit number. 1247 * flags - Flags to decide Ethernet driving TVCO rate. (PM8X50_TVCO_SUPPORT_20P625G) 1248 * vco - VCO rate to check. 1249 */ 1250 STATIC 1251 int _pm8x50_ethernet_tvco_check(int unit, 1252 uint32 flags, 1253 portmod_vco_type_t vco) 1254 { 1255 if (PM8X50_TVCO_SUPPORT_20P625G_GET(flags)) { 1256 return ((vco == portmodVCO25P781G) || 1257 (vco == portmodVCO26P562G) || 1258 (vco == portmodVCO20P625G)); 1259 } else { 1260 return ((vco == portmodVCO25P781G) || (vco == portmodVCO26P562G)); 1261 } 1262 1263 } 1264 1265 /*Get whether the inerface type is supported by PM */ 1266 int pm8x50_pm_interface_type_is_supported(int unit, 1267 soc_port_if_t interface, 1268 int* is_supported) 1269 { 1270 1271 switch(interface){ 1272 case SOC_PORT_IF_ILKN: 1273 *is_supported = FALSE; 1274 break; 1275 default: 1276 *is_supported = TRUE; 1277 } 1278 1279 return (SOC_E_NONE); 1280 } 1281 1282 STATIC int 1283 pm8x50_default_fw_loader(const phymod_core_access_t* core, uint32_t length, const uint8_t* data) 1284 { 1285 int rv, bcast_en = 0; 1286 portmod_default_user_access_t *user_data; 1287 int unit = ((portmod_default_user_access_t*)core->access.user_acc)->unit; 1288 portmod_ucode_buf_order_t load_order; 1289 SOC_INIT_FUNC_DEFS; 1290 1291 user_data = (portmod_default_user_access_t*)core->access.user_acc; 1292 1293 if (PORTMOD_USER_ACCESS_FW_LOAD_REVERSE_GET(user_data)) { 1294 load_order = portmod_ucode_buf_order_reversed; 1295 } else { 1296 load_order = portmod_ucode_buf_order_straight; 1297 } 1298 1299 rv = portmod_firmware_set(unit, 1300 user_data->blk_id, 1301 data, 1302 length, 1303 load_order, 1304 bcast_en, 1305 &(pm8x50_ucode_buf[unit]), 1306 &(pm8x50_ucode_buf_2nd[unit]), 1307 CDPORT_TSC_UCMEM_DATAm, 1308 CDPORT_TSC_MEM_CTRLr); 1309 _SOC_IF_ERR_EXIT(rv); 1310 1311 exit: 1312 SOC_FUNC_RETURN; 1313 } 1314 1315 1316 STATIC 1317 int 1318 pm8x50_default_bus_write(void* user_acc, uint32_t core_addr, uint32_t reg_addr, 1319 uint32_t val) 1320 { 1321 /* will force the core_addr to zero since it's NOT being used */ 1322 return portmod_common_phy_sbus_reg_write(CDPORT_TSC_UCMEM_DATAm, user_acc, 1323 0x0, reg_addr, val); 1324 } 1325 1326 STATIC 1327 int 1328 pm8x50_default_mem_write(void* user_acc, 1329 phymod_mem_type_t mem_type, 1330 uint32_t mem_index, 1331 const uint32_t* val) 1332 { 1333 int rv = SOC_E_NONE; 1334 soc_mem_t tsc_mem_data; 1335 const uint32_t *array_ptr; 1336 portmod_default_user_access_t *user_data = user_acc; 1337 1338 if(user_data == NULL){ 1339 return SOC_E_PARAM; 1340 } 1341 1342 /* sanity check on the mem_type */ 1343 if (mem_type >= phymodMemCount) { 1344 return SOC_E_PARAM; 1345 } 1346 1347 /*next check if simulation */ 1348 if (SAL_BOOT_QUICKTURN) { 1349 return SOC_E_NONE; 1350 } 1351 1352 /* next need to map to the correct memory */ 1353 switch (mem_type) { 1354 case phymodMemSpeedIdTable: 1355 tsc_mem_data = SPEED_ID_TABLEm; 1356 break; 1357 case phymodMemAMTable: 1358 tsc_mem_data = AM_TABLEm; 1359 break; 1360 case phymodMemUMTable: 1361 tsc_mem_data = UM_TABLEm; 1362 break; 1363 case phymodMemTxLkup1588Mpp0: 1364 tsc_mem_data = TX_LKUP_1588_MEM_MPP0m; 1365 break; 1366 case phymodMemTxLkup1588Mpp1: 1367 tsc_mem_data = TX_LKUP_1588_MEM_MPP1m; 1368 break; 1369 case phymodMemTxLkup1588400G: 1370 tsc_mem_data = TX_LKUP_1588_MEM_400Gm; 1371 break; 1372 case phymodMemRxLkup1588Mpp0: 1373 tsc_mem_data = RX_LKUP_1588_MEM_MPP0m; 1374 break; 1375 case phymodMemRxLkup1588Mpp1: 1376 tsc_mem_data = RX_LKUP_1588_MEM_MPP1m; 1377 break; 1378 case phymodMemRxLkup1588400G: 1379 tsc_mem_data = RX_LKUP_1588_MEM_400Gm; 1380 break; 1381 case phymodMemSpeedPriorityMapTable: 1382 tsc_mem_data = SPEED_PRIORITY_MAP_TBLm; 1383 break; 1384 default: 1385 return SOC_E_PARAM; 1386 } 1387 array_ptr = val; 1388 1389 rv = soc_mem_write(user_data->unit, tsc_mem_data, user_data->blk_id, mem_index, (void *) &array_ptr[0]); 1390 1391 return rv; 1392 } 1393 1394 1395 STATIC 1396 int 1397 pm8x50_default_bus_read(void* user_acc, uint32_t core_addr, uint32_t reg_addr, 1398 uint32_t *val) 1399 { 1400 int rv = SOC_E_NONE; 1401 1402 /* will force the core_addr to zero since it's NOT being used */ 1403 rv = portmod_common_phy_sbus_reg_read(CDPORT_TSC_UCMEM_DATAm, user_acc, 1404 0x0, reg_addr, val); 1405 /* needs to down shift read by 16 bit due to pm8x50 HW change */ 1406 *val = (*val >> 16) & 0xffff; 1407 return (rv); 1408 } 1409 1410 STATIC 1411 int 1412 pm8x50_default_mem_read(void* user_acc, 1413 phymod_mem_type_t mem_type, 1414 uint32_t mem_index, 1415 uint32_t* val) 1416 { 1417 int rv = SOC_E_NONE; 1418 soc_mem_t tsc_mem_data; 1419 portmod_default_user_access_t *user_data = user_acc; 1420 1421 if(user_data == NULL){ 1422 return SOC_E_PARAM; 1423 } 1424 /* sanity check on the mem_type */ 1425 if (mem_type >= phymodMemCount) { 1426 return SOC_E_PARAM; 1427 } 1428 1429 /*next check if simulation */ 1430 if (SAL_BOOT_QUICKTURN) { 1431 return SOC_E_NONE; 1432 } 1433 1434 /* next need to map to the correct memory */ 1435 switch (mem_type) { 1436 case phymodMemSpeedIdTable: 1437 tsc_mem_data = SPEED_ID_TABLEm; 1438 break; 1439 case phymodMemAMTable: 1440 tsc_mem_data = AM_TABLEm; 1441 break; 1442 case phymodMemUMTable: 1443 tsc_mem_data = UM_TABLEm; 1444 break; 1445 case phymodMemTxLkup1588Mpp0: 1446 tsc_mem_data = TX_LKUP_1588_MEM_MPP0m; 1447 break; 1448 case phymodMemTxLkup1588Mpp1: 1449 tsc_mem_data = TX_LKUP_1588_MEM_MPP1m; 1450 break; 1451 case phymodMemTxLkup1588400G: 1452 tsc_mem_data = TX_LKUP_1588_MEM_400Gm; 1453 break; 1454 case phymodMemRxLkup1588Mpp0: 1455 tsc_mem_data = RX_LKUP_1588_MEM_MPP0m; 1456 break; 1457 case phymodMemRxLkup1588Mpp1: 1458 tsc_mem_data = RX_LKUP_1588_MEM_MPP1m; 1459 break; 1460 case phymodMemRxLkup1588400G: 1461 tsc_mem_data = RX_LKUP_1588_MEM_400Gm; 1462 break; 1463 case phymodMemSpeedPriorityMapTable: 1464 tsc_mem_data = SPEED_PRIORITY_MAP_TBLm; 1465 break; 1466 default: 1467 return SOC_E_PARAM; 1468 } 1469 1470 rv = soc_mem_read(user_data->unit, tsc_mem_data, user_data->blk_id, mem_index, val); 1471 1472 return rv; 1473 } 1474 1475 1476 /* 1477 * Function: 1478 * portmod_pm8x50_wb_upgrade_func 1479 * Purpose: 1480 * This function will take care of the warmboot variable manipulation 1481 * in case of upgrade case, when variable definition got change or 1482 * unspoorted varaible from previous version. 1483 * Parameters: 1484 * unit -(IN) Device unit number . 1485 * arg -(IN) Generic pointer for a specific module to be used 1486 * recovered_version -(IN) Warmboot version of the existing data. 1487 * new_version -(IN) Warmboot version of new data. 1488 * Returns: 1489 * Status 1490 */ 1491 1492 int portmod_pm8x50_wb_upgrade_func(int unit, void *arg, int recovered_version, 1493 int new_version) 1494 { 1495 pm_info_t pm_info; 1496 int port_is_pcs_bypased; 1497 int i, ts_enable_port_count; 1498 uint32 fec_null, timesync_enable; 1499 int remote_pause; 1500 1501 SOC_INIT_FUNC_DEFS; 1502 1503 pm_info = arg; 1504 1505 if ((recovered_version <= 1) && 1506 (new_version >= 2)) { 1507 ts_enable_port_count = 0; 1508 fec_null = 0; 1509 timesync_enable = 0; 1510 _SOC_IF_ERR_EXIT( 1511 PM8x50_TS_ENABLE_PORT_COUNT_SET(unit, pm_info, ts_enable_port_count)); 1512 1513 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 1514 _SOC_IF_ERR_EXIT( 1515 PM8x50_LANE2FEC_SET(unit, pm_info, i, fec_null)); 1516 _SOC_IF_ERR_EXIT( 1517 PM8x50_TIMESYNC_ENABLE_SET(unit, pm_info, timesync_enable, i)); 1518 } 1519 } 1520 if ((recovered_version <= 2) && 1521 (new_version >= 3)) { 1522 port_is_pcs_bypased = 0; 1523 1524 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 1525 _SOC_IF_ERR_EXIT( 1526 PM8x50_PORT_IS_PCS_BYPASSED_SET(unit, pm_info, port_is_pcs_bypased, i)); 1527 } 1528 } 1529 if ((recovered_version <= 3) && 1530 (new_version >= 4)) { 1531 remote_pause = 0; 1532 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 1533 _SOC_IF_ERR_EXIT( 1534 PM8x50_400G_AN_REMOTE_PAUSE_SET(unit, pm_info, remote_pause, i)); 1535 } 1536 } 1537 1538 exit: 1539 SOC_FUNC_RETURN; 1540 } 1541 1542 /* 1543 * Initialize the buffer to support warmboot 1544 * The state of warmboot is store in the variables like 1545 * isInitialized, isActive, portIsPcsBypassed, ports.. etc., 1546 * All of these variables need to be added to warmboot 1547 * any variables added to save the state of warmboot should be 1548 * included here. 1549 */ 1550 STATIC 1551 int pm8x50_wb_buffer_init(int unit, int wb_buffer_index, pm_info_t pm_info) 1552 { 1553 /* Declare the common variables needed for warmboot */ 1554 WB_ENGINE_INIT_TABLES_DEFS; 1555 int wb_var_id, rv; 1556 int buffer_id = wb_buffer_index; /*required by SOC_WB_ENGINE_ADD_ Macros*/ 1557 SOC_INIT_FUNC_DEFS; 1558 1559 COMPILER_REFERENCE(buffer_is_dynamic); 1560 1561 SOC_WB_ENGINE_ADD_BUFF(SOC_WB_ENGINE_PORTMOD, wb_buffer_index, "pm8x50", 1562 portmod_pm8x50_wb_upgrade_func, pm_info, 1563 PM8x50_WB_BUFFER_VERSION, 1, 1564 SOC_WB_ENGINE_PRE_RELEASE); 1565 _SOC_IF_ERR_EXIT(rv); 1566 1567 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1568 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, 1569 "is_core_initialized", wb_buffer_index, sizeof(int), 1570 NULL, MAX_PORTS_PER_PM8X50, VERSION(1)); 1571 _SOC_IF_ERR_EXIT(rv); 1572 pm_info->wb_vars_ids[isCoreInitialized] = wb_var_id; 1573 1574 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1575 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "is_active", 1576 wb_buffer_index, sizeof(uint32), NULL, VERSION(1)); 1577 _SOC_IF_ERR_EXIT(rv); 1578 pm_info->wb_vars_ids[isActive] = wb_var_id; 1579 1580 /* "isBypassed" has been not supported from version 3 */ 1581 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1582 SOC_WB_ENGINE_REMOVED_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "is_bypassed", wb_buffer_index, sizeof(uint32), 1583 NULL, 1, VERSION(1), VERSION(3)); 1584 _SOC_IF_ERR_EXIT(rv); 1585 pm_info->wb_vars_ids[isBypassed] = wb_var_id; 1586 1587 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1588 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "ovco_pll_active_lane_bitmap", 1589 wb_buffer_index, sizeof(uint8), NULL, VERSION(1)); 1590 _SOC_IF_ERR_EXIT(rv); 1591 pm_info->wb_vars_ids[ovcopllActiveLaneBitmap] = wb_var_id; 1592 1593 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1594 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "tvco_pll_active_lane_bitmap", 1595 wb_buffer_index, sizeof(uint8), NULL, VERSION(1)); 1596 _SOC_IF_ERR_EXIT(rv); 1597 pm_info->wb_vars_ids[tvcopllActiveLaneBitmap] = wb_var_id; 1598 1599 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1600 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "ovco_pll_adv_lane_bitmap", 1601 wb_buffer_index, sizeof(uint8), NULL, VERSION(1)); 1602 _SOC_IF_ERR_EXIT(rv); 1603 pm_info->wb_vars_ids[ovcopllAdvLaneBitmap] = wb_var_id; 1604 1605 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1606 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "tvco_pll_adv_lane_bitmap", 1607 wb_buffer_index, sizeof(uint8), NULL, VERSION(1)); 1608 _SOC_IF_ERR_EXIT(rv); 1609 pm_info->wb_vars_ids[tvcopllAdvLaneBitmap] = wb_var_id; 1610 1611 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1612 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "lane2portMap", 1613 wb_buffer_index, sizeof(int), NULL, MAX_PORTS_PER_PM8X50, VERSION(1)); 1614 _SOC_IF_ERR_EXIT(rv); 1615 pm_info->wb_vars_ids[lane2portMap] = wb_var_id; 1616 1617 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1618 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "max_speed", 1619 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(1)); 1620 _SOC_IF_ERR_EXIT(rv); 1621 pm_info->wb_vars_ids[maxSpeed] = wb_var_id; 1622 1623 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1624 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "an_mode", 1625 wb_buffer_index, sizeof(int), NULL, MAX_PORTS_PER_PM8X50, VERSION(1)); 1626 _SOC_IF_ERR_EXIT(rv); 1627 pm_info->wb_vars_ids[anMode] = wb_var_id; 1628 1629 /* Deleting below 2 WB structures since they are not needed. */ 1630 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1631 SOC_WB_ENGINE_REMOVED_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "an_fec", wb_buffer_index, sizeof(uint32), 1632 NULL, MAX_PORTS_PER_PM8X50, VERSION(1), VERSION(2)); 1633 _SOC_IF_ERR_EXIT(rv); 1634 pm_info->wb_vars_ids[anFec] = wb_var_id; 1635 1636 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1637 SOC_WB_ENGINE_REMOVED_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "fs_cl72", wb_buffer_index, sizeof(uint32), 1638 NULL, MAX_PORTS_PER_PM8X50, VERSION(1), VERSION(2)); 1639 _SOC_IF_ERR_EXIT(rv); 1640 pm_info->wb_vars_ids[fsCl72] = wb_var_id; 1641 1642 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1643 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "lane2fecMap", 1644 wb_buffer_index, sizeof(int), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1645 _SOC_IF_ERR_EXIT(rv); 1646 pm_info->wb_vars_ids[lane2fecMap] = wb_var_id; 1647 1648 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1649 1650 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "ts_enable_port_count", 1651 wb_buffer_index, sizeof(int), NULL, VERSION(2)); 1652 _SOC_IF_ERR_EXIT(rv); 1653 pm_info->wb_vars_ids[tsEnablePortCount] = wb_var_id; 1654 1655 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1656 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "timesync_enable", 1657 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1658 _SOC_IF_ERR_EXIT(rv); 1659 pm_info->wb_vars_ids[timesyncEnable] = wb_var_id; 1660 1661 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1662 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "rlm_enabled", 1663 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1664 _SOC_IF_ERR_EXIT(rv); 1665 pm_info->wb_vars_ids[rlmEnable] = wb_var_id; 1666 1667 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1668 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "is_initiator", 1669 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1670 _SOC_IF_ERR_EXIT(rv); 1671 pm_info->wb_vars_ids[initiator] = wb_var_id; 1672 1673 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1674 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "pcs_reconfigured", 1675 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1676 _SOC_IF_ERR_EXIT(rv); 1677 pm_info->wb_vars_ids[pcsReconfigured] = wb_var_id; 1678 1679 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1680 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "active_lame_map", 1681 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1682 _SOC_IF_ERR_EXIT(rv); 1683 pm_info->wb_vars_ids[activeLaneBitMap] = wb_var_id; 1684 1685 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1686 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "rlm_state", 1687 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1688 _SOC_IF_ERR_EXIT(rv); 1689 pm_info->wb_vars_ids[rlmState] = wb_var_id; 1690 1691 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1692 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "fec_type", 1693 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1694 _SOC_IF_ERR_EXIT(rv); 1695 pm_info->wb_vars_ids[originalFec] = wb_var_id; 1696 1697 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1698 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "tx_lane_swap", 1699 wb_buffer_index, sizeof(int), NULL, VERSION(2)); 1700 _SOC_IF_ERR_EXIT(rv); 1701 pm_info->wb_vars_ids[originalTxLaneSwap] = wb_var_id; 1702 1703 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1704 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "rx_lane_swap", 1705 wb_buffer_index, sizeof(int), NULL, VERSION(2)); 1706 _SOC_IF_ERR_EXIT(rv); 1707 pm_info->wb_vars_ids[originalRxLaneSwap] = wb_var_id; 1708 1709 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1710 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "400g_an_enable", 1711 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(2)); 1712 _SOC_IF_ERR_EXIT(rv); 1713 pm_info->wb_vars_ids[is400gAn] = wb_var_id; 1714 1715 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1716 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "an_state_400g", 1717 wb_buffer_index, sizeof(int), NULL, VERSION(2)); 1718 _SOC_IF_ERR_EXIT(rv); 1719 pm_info->wb_vars_ids[anState400g] = wb_var_id; 1720 1721 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1722 SOC_WB_ENGINE_ADD_VAR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "an_wait_link_count", 1723 wb_buffer_index, sizeof(int), NULL, VERSION(2)); 1724 _SOC_IF_ERR_EXIT(rv); 1725 pm_info->wb_vars_ids[anWaitlinkCount] = wb_var_id; 1726 1727 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1728 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "port_is_pcs_bypassed", 1729 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(3)); 1730 _SOC_IF_ERR_EXIT(rv); 1731 pm_info->wb_vars_ids[portIsPcsBypassed] = wb_var_id; 1732 1733 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1734 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "is_ber_war_enable", 1735 wb_buffer_index, sizeof(uint32), NULL, MAX_PORTS_PER_PM8X50, VERSION(4)); 1736 _SOC_IF_ERR_EXIT(rv); 1737 pm_info->wb_vars_ids[isBerWarEnable] = wb_var_id; 1738 1739 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1740 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "ber_war_state", 1741 wb_buffer_index, sizeof(int), NULL, MAX_PORTS_PER_PM8X50, VERSION(4)); 1742 _SOC_IF_ERR_EXIT(rv); 1743 pm_info->wb_vars_ids[berWarState] = wb_var_id; 1744 1745 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1746 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "ber_war_wait_count", 1747 wb_buffer_index, sizeof(int), NULL, MAX_PORTS_PER_PM8X50, VERSION(4)); 1748 _SOC_IF_ERR_EXIT(rv); 1749 pm_info->wb_vars_ids[berWarWaitCount] = wb_var_id; 1750 1751 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, 1752 "is_core_flexe_configured", wb_buffer_index, sizeof(int), 1753 NULL, MAX_PORTS_PER_PM8X50, VERSION(4)); 1754 _SOC_IF_ERR_EXIT(rv); 1755 pm_info->wb_vars_ids[coreisFlexeConfigured] = wb_var_id; 1756 1757 _SOC_IF_ERR_EXIT(portmod_next_wb_var_id_get(unit, &wb_var_id)); 1758 SOC_WB_ENGINE_ADD_ARR(SOC_WB_ENGINE_PORTMOD, wb_var_id, "an_400g_remote_pause", 1759 wb_buffer_index, sizeof(int), NULL, MAX_PORTS_PER_PM8X50, VERSION(4)); 1760 _SOC_IF_ERR_EXIT(rv); 1761 pm_info->wb_vars_ids[an400gRemotePause] = wb_var_id; 1762 1763 _SOC_IF_ERR_EXIT(soc_wb_engine_init_buffer(unit, SOC_WB_ENGINE_PORTMOD, 1764 wb_buffer_index, FALSE)); 1765 1766 exit: 1767 SOC_FUNC_RETURN; 1768 } 1769 1770 phymod_bus_t pm8x50_default_bus = { 1771 "PM8x50 Bus", 1772 pm8x50_default_bus_read, 1773 pm8x50_default_bus_write, 1774 NULL, 1775 portmod_common_mutex_take, 1776 portmod_common_mutex_give, 1777 pm8x50_default_mem_read, 1778 pm8x50_default_mem_write, 1779 PHYMOD_BUS_CAP_WR_MODIFY | PHYMOD_BUS_CAP_LANE_CTRL 1780 }; 1781 1782 STATIC 1783 int _pm8x50_pll_to_vco_get(phymod_ref_clk_t ref_clock, uint32_t pll, portmod_vco_type_t* vco) 1784 { 1785 int rv = SOC_E_NONE; 1786 1787 if (ref_clock == phymodRefClk156Mhz) { 1788 switch (pll) { 1789 case phymod_TSCBH_PLL_DIV132: 1790 *vco = portmodVCO20P625G; 1791 break; 1792 case phymod_TSCBH_PLL_DIV165: 1793 *vco = portmodVCO25P781G; 1794 break; 1795 case phymod_TSCBH_PLL_DIV170: 1796 *vco = portmodVCO26P562G; 1797 break; 1798 case phymod_TSCBH_PLL_DIV160: 1799 *vco = portmodVCO25G; 1800 break; 1801 case phymod_TSCBH_PLL_DIV175: 1802 *vco = portmodVCO27P343G; 1803 break; 1804 case phymod_TSCBH_PLL_DIV180: 1805 *vco = portmodVCO28P125G; 1806 break; 1807 default: 1808 rv = SOC_E_PARAM; 1809 } 1810 } else if (ref_clock == phymodRefClk312Mhz) { 1811 switch (pll) { 1812 case phymod_TSCBH_PLL_DIV66: 1813 *vco = portmodVCO20P625G; 1814 break; 1815 case phymod_TSCBH_PLL_DIV82P5: 1816 *vco = portmodVCO25P781G; 1817 break; 1818 case phymod_TSCBH_PLL_DIV85: 1819 *vco = portmodVCO26P562G; 1820 break; 1821 case phymod_TSCBH_PLL_DIV80: 1822 *vco = portmodVCO25G; 1823 break; 1824 case phymod_TSCBH_PLL_DIV87P5: 1825 *vco = portmodVCO27P343G; 1826 break; 1827 case phymod_TSCBH_PLL_DIV90: 1828 *vco = portmodVCO28P125G; 1829 break; 1830 default: 1831 rv = SOC_E_PARAM; 1832 } 1833 } else { 1834 rv = SOC_E_PARAM; 1835 } 1836 1837 return rv; 1838 } 1839 1840 /* Translate phymod_fec type to portmod_fec_type */ 1841 STATIC 1842 int _pm8x50_port_phy_to_port_fec(phymod_fec_type_t phymod_fec, portmod_fec_t* portmod_fec) 1843 { 1844 int rv = SOC_E_NONE; 1845 if (phymod_fec == phymod_fec_None) { 1846 *portmod_fec = PORTMOD_PORT_PHY_FEC_NONE; 1847 } else if (phymod_fec == phymod_fec_CL74) { 1848 *portmod_fec = PORTMOD_PORT_PHY_FEC_BASE_R; 1849 } else if (phymod_fec == phymod_fec_CL91) { 1850 *portmod_fec = PORTMOD_PORT_PHY_FEC_RS_FEC; 1851 } else if (phymod_fec == phymod_fec_RS544) { 1852 *portmod_fec = PORTMOD_PORT_PHY_FEC_RS_544; 1853 } else if (phymod_fec == phymod_fec_RS272) { 1854 *portmod_fec = PORTMOD_PORT_PHY_FEC_RS_272; 1855 } else if (phymod_fec == phymod_fec_RS544_2XN) { 1856 *portmod_fec = PORTMOD_PORT_PHY_FEC_RS_544_2XN; 1857 } else if (phymod_fec == phymod_fec_RS272_2XN) { 1858 *portmod_fec = PORTMOD_PORT_PHY_FEC_RS_272_2XN; 1859 } else { 1860 rv = SOC_E_PARAM; 1861 } 1862 return rv; 1863 } 1864 1865 1866 1867 /* this function is to manage the RLM state machine during PORT 1868 transition into RLM mode 1869 */ 1870 1871 int pm8x50_port_rlm_state_update(int unit, int port, pm_info_t pm_info, int *is_done) 1872 { 1873 portmod_access_get_params_t params; 1874 phymod_phy_access_t phy_access, phy_copy; 1875 uint32 rval, is_initiator, pcs_is_reconfigured, active_lane_map, active_lane_num; 1876 phymod_fec_type_t FecType; 1877 uint32 txLaneSwap, rxLaneSwap, bitmap, prbs_active_lane_num = 0, prbs_active_lane_map = 0x0, num_lane = 0; 1878 portmod_port_rlm_state_t local_port_rlm_state; 1879 int nof_phys, port_index = -1, mac_link = 0; 1880 uint32 prbs_flag = 0x0, i; 1881 phymod_prbs_t prbs_config; 1882 phymod_prbs_status_t prbs_status; 1883 char* state_string = " \n"; 1884 1885 1886 SOC_INIT_FUNC_DEFS; 1887 1888 *is_done = 0; 1889 1890 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 1891 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 1892 ¶ms, 1, &phy_access, &nof_phys, NULL)); 1893 1894 sal_memcpy(&phy_copy, &phy_access, sizeof(phy_copy)); 1895 1896 /* need to know if 4 lane or 8 lane port and also start lane of this port */ 1897 PORTMOD_BIT_COUNT(phy_access.access.lane_mask, num_lane); 1898 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 1899 1900 /* first get all the RLM warmboot variable */ 1901 _SOC_IF_ERR_EXIT 1902 (PM8x50_INITIATOR_GET(unit, pm_info, &is_initiator, port_index)); 1903 1904 _SOC_IF_ERR_EXIT 1905 (PM8x50_PCS_RECONFIG_GET(unit, pm_info, &pcs_is_reconfigured, port_index)); 1906 1907 _SOC_IF_ERR_EXIT 1908 (PM8x50_ACTIVE_LANE_MAP_GET(unit, pm_info, &active_lane_map, port_index)); 1909 1910 _SOC_IF_ERR_EXIT 1911 (PM8x50_RLM_STATE_GET(unit, pm_info, &local_port_rlm_state.rlm_state, port_index)); 1912 1913 _SOC_IF_ERR_EXIT 1914 (PM8x50_ORIGINAL_FEC_GET(unit, pm_info, &FecType, port_index)); 1915 1916 _SOC_IF_ERR_EXIT 1917 (PM8x50_ORIG_TX_LANE_MAP_GET(unit, pm_info, &txLaneSwap)); 1918 1919 _SOC_IF_ERR_EXIT 1920 (PM8x50_ORIG_RX_LANE_MAP_GET(unit, pm_info, &rxLaneSwap)); 1921 1922 /* get the active lane number */ 1923 active_lane_num = 0; 1924 for (i = 0; i < num_lane; i++) { 1925 if (active_lane_map & 1 << (port_index + i)) { 1926 active_lane_num++; 1927 } 1928 } 1929 1930 /* first thing is to check MAC link status */ 1931 if (port_index == 4) { 1932 _SOC_IF_ERR_EXIT( 1933 READ_CDPORT_XGXS0_LN4_STATUS_REGr(unit, port, &rval)); 1934 mac_link = soc_reg_field_get(unit, CDPORT_XGXS0_LN4_STATUS_REGr, rval, LINK_STATUSf); 1935 1936 } else { 1937 _SOC_IF_ERR_EXIT( 1938 READ_CDPORT_XGXS0_LN0_STATUS_REGr(unit, port, &rval)); 1939 mac_link = soc_reg_field_get(unit, CDPORT_XGXS0_LN0_STATUS_REGr, rval, LINK_STATUSf); 1940 } 1941 1942 /* if mac link status ever go low, directly go to error state */ 1943 if (!mac_link) { 1944 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_ERROR; 1945 } else { 1946 /* RLM state machine update */ 1947 switch (local_port_rlm_state.rlm_state) { 1948 case PORTMOD_PORT_RLM_SEND_PACKET_DATA: 1949 state_string ="SEND_PACKET_DATA"; 1950 /* first disable tx stall */ 1951 _SOC_IF_ERR_EXIT 1952 (cdmac_tx_stall_enable_set(unit, port, 0)); 1953 1954 /* first check initiator set or not */ 1955 if (is_initiator) { 1956 /* update the state */ 1957 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_STOP_MAC; 1958 } else { /* follower */ 1959 /* first if link interruption status */ 1960 uint32 li_status = 0; 1961 _SOC_IF_ERR_EXIT 1962 (cdmac_link_interruption_live_status_get(unit, port, &li_status)); 1963 if (li_status) { 1964 /* update the state */ 1965 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_STOP_MAC; 1966 } 1967 } 1968 break; 1969 case PORTMOD_PORT_RLM_STOP_MAC: 1970 state_string ="STOP_MAC"; 1971 /* clear the pcs reconfigured */ 1972 pcs_is_reconfigured = FALSE; 1973 /* enable tx stall */ 1974 _SOC_IF_ERR_EXIT 1975 (cdmac_tx_stall_enable_set(unit, port, 1)); 1976 /* update the state to SEND_LI*/ 1977 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_LI; 1978 break; 1979 case PORTMOD_PORT_RLM_SEND_LI: 1980 { 1981 uint32 li_enable = 0, prbs_enabled = 0, li_status; 1982 int pcs_link = 0; 1983 1984 state_string ="SEND_LI"; 1985 1986 /* first check if LI is enabled or not */ 1987 _SOC_IF_ERR_EXIT 1988 (cdmac_link_interrupt_ordered_set_enable_get(unit, port, &li_enable)); 1989 if (!li_enable) { 1990 _SOC_IF_ERR_EXIT 1991 (cdmac_link_interrupt_ordered_set_enable(unit, port, 1)); 1992 } 1993 /*next check if initiator */ 1994 if (is_initiator) { 1995 /* if initiator, then check pcs reconfigured status */ 1996 if (pcs_is_reconfigured) { 1997 /*next need to check prbs status */ 1998 _SOC_IF_ERR_EXIT 1999 (phymod_phy_prbs_enable_get(&phy_access, 0, &prbs_enabled)); 2000 if (prbs_enabled) { 2001 /* disable prbs for both tx/rx */ 2002 _SOC_IF_ERR_EXIT 2003 (phymod_phy_prbs_enable_set(&phy_access, 0, 0)); 2004 /* disable the tx/disable and lane dp reset override */ 2005 _SOC_IF_ERR_EXIT 2006 (phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDLaneReset, 0, 0)); 2007 _SOC_IF_ERR_EXIT 2008 (phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDTxDisable, 0, 0)); 2009 } 2010 /* next poll the pcs link status and LI status */ 2011 _SOC_IF_ERR_EXIT 2012 (cdmac_link_interruption_live_status_get(unit, port, &li_status)); 2013 /* read twice the pcs link status */ 2014 _SOC_IF_ERR_EXIT 2015 (pm8x50_port_link_get(unit, port, pm_info, 0, &pcs_link)); 2016 _SOC_IF_ERR_EXIT 2017 (pm8x50_port_link_get(unit, port, pm_info, 0, &pcs_link)); 2018 if (li_status && pcs_link) { 2019 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_IDLE; 2020 } 2021 } else { /* pcs is not reconfigured */ 2022 /* need to check LI status */ 2023 _SOC_IF_ERR_EXIT 2024 (cdmac_link_interruption_live_status_get(unit, port, &li_status)); 2025 if (li_status) { 2026 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_PRBS; 2027 } 2028 } 2029 } else { /*non initiator */ 2030 if (pcs_is_reconfigured) { 2031 /*next need to check prbs status */ 2032 _SOC_IF_ERR_EXIT 2033 (phymod_phy_prbs_enable_get(&phy_access, 0, &prbs_enabled)); 2034 if (prbs_enabled) { 2035 /* disable prbs for both tx/rx */ 2036 _SOC_IF_ERR_EXIT 2037 (phymod_phy_prbs_enable_set(&phy_access, 0, 0)); 2038 /* disable the tx/disable and lane dp reset override */ 2039 _SOC_IF_ERR_EXIT 2040 (phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDLaneReset, 0, 0)); 2041 _SOC_IF_ERR_EXIT 2042 (phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDTxDisable, 0, 0)); 2043 } 2044 /* next poll the pcs link status and LI status */ 2045 _SOC_IF_ERR_EXIT 2046 (cdmac_link_interruption_live_status_get(unit, port, &li_status)); 2047 /* read twice the pcs link status */ 2048 _SOC_IF_ERR_EXIT 2049 (pm8x50_port_link_get(unit, port, pm_info, 0, &pcs_link)); 2050 _SOC_IF_ERR_EXIT 2051 (pm8x50_port_link_get(unit, port, pm_info, 0, &pcs_link)); 2052 if (li_status && pcs_link) { 2053 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_IDLE; 2054 } 2055 } else { /* pcs is not reconfigured yet */ 2056 uint32 prbs_active_lane_num = 0, prbs_active_lane_map = 0x0, pmd_lock = 0; 2057 prbs_flag = 0x0; 2058 2059 /* first set RX prbs only and check if rx prbs is enabled or not*/ 2060 PHYMOD_PRBS_DIRECTION_RX_SET(prbs_flag); 2061 _SOC_IF_ERR_EXIT 2062 (phymod_phy_prbs_enable_get(&phy_access, prbs_flag, &prbs_enabled)); 2063 if (!prbs_enabled) { 2064 prbs_config.poly = phymodPrbsPoly13; 2065 prbs_config.invert = 0; 2066 _SOC_IF_ERR_EXIT 2067 (phymod_phy_prbs_config_set(&phy_access, prbs_flag, &prbs_config)); 2068 _SOC_IF_ERR_EXIT 2069 (phymod_phy_prbs_enable_set(&phy_access, prbs_flag, 1)); 2070 } 2071 2072 /*before check the prbs status, make sure signal detection are valid on all lanes*/ 2073 _SOC_IF_ERR_EXIT 2074 (phymod_phy_rx_pmd_locked_get(&phy_access, &pmd_lock)); 2075 sal_usleep(100); 2076 _SOC_IF_ERR_EXIT 2077 (phymod_phy_rx_pmd_locked_get(&phy_access, &pmd_lock)); 2078 2079 /* next check per lane prbs status only if PMD is locked */ 2080 if ((pmd_lock) && (!is_initiator)) { 2081 /* next check per lane prbs status */ 2082 for (i = 0; i < num_lane; i ++) { 2083 phy_copy.access.lane_mask = 1 << (i + port_index); 2084 /*first read clear the status */ 2085 _SOC_IF_ERR_EXIT 2086 (phymod_phy_prbs_status_get(&phy_copy, 0, &prbs_status)); 2087 2088 sal_usleep(100); 2089 2090 _SOC_IF_ERR_EXIT 2091 (phymod_phy_prbs_status_get(&phy_copy, 0, &prbs_status)); 2092 /* next check the lock status */ 2093 if (prbs_status.prbs_lock) { 2094 prbs_active_lane_num++; 2095 prbs_active_lane_map |= 1 << (i + port_index); 2096 } 2097 } 2098 /* next check active lane PRBS status */ 2099 if ( ((num_lane == 4) && (prbs_active_lane_num == 3)) || 2100 ((num_lane == 4) && (prbs_active_lane_num == 4)) || 2101 ((num_lane == 8) && (prbs_active_lane_num == 8)) || 2102 ((num_lane == 8) && (prbs_active_lane_num == 6)) || 2103 ((num_lane == 8) && (prbs_active_lane_num == 7)) ) { 2104 2105 if (active_lane_map == prbs_active_lane_map) { 2106 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_PRBS; 2107 } else { 2108 active_lane_map = prbs_active_lane_map; 2109 } 2110 } 2111 } 2112 } /* end of pcs not configured for follower */ 2113 } 2114 break; 2115 } /* end of this LI case */ 2116 case PORTMOD_PORT_RLM_SEND_PRBS: 2117 { 2118 uint32 first_active_lane_num = 0, prbs_enabled = 0, need_reconfig_pcs = 0; 2119 int follower_prbs_resend = 0; 2120 prbs_flag = 0; 2121 2122 state_string ="SEND_PRBS"; 2123 2124 /*first for follower check the prbs lane active map */ 2125 if ((!is_initiator) && (!pcs_is_reconfigured)) { 2126 /* next check per lane prbs status */ 2127 for (i = 0; i < num_lane; i ++) { 2128 phy_copy.access.lane_mask = 1 << (i + port_index); 2129 /*first read clear the status */ 2130 _SOC_IF_ERR_EXIT 2131 (phymod_phy_prbs_status_get(&phy_copy, 0, &prbs_status)); 2132 2133 sal_usleep(100); 2134 /* next read the status */ 2135 _SOC_IF_ERR_EXIT 2136 (phymod_phy_prbs_status_get(&phy_copy, 0, &prbs_status)); 2137 /*first read clear the status */ 2138 /* next check the lock status */ 2139 if (prbs_status.prbs_lock) { 2140 prbs_active_lane_num++; 2141 prbs_active_lane_map |= 1 << (i + port_index); 2142 } 2143 } 2144 2145 if ((prbs_active_lane_map != active_lane_map) && (prbs_active_lane_map != 0x0)) { 2146 active_lane_map = prbs_active_lane_map; 2147 follower_prbs_resend = 1; 2148 } 2149 } 2150 2151 /* first set TX prbs only and check if tx prbs is enabled or not*/ 2152 /* only if the pcs is not reconfigured */ 2153 if (!pcs_is_reconfigured) { 2154 for (i = 0; i < num_lane; i++) { 2155 if (active_lane_map & 1 << (port_index + i)) { 2156 first_active_lane_num = port_index + i; 2157 break; 2158 } 2159 } 2160 PHYMOD_PRBS_DIRECTION_TX_SET(prbs_flag); 2161 phy_copy.access.lane_mask = 1 << first_active_lane_num; 2162 _SOC_IF_ERR_EXIT 2163 (phymod_phy_prbs_enable_get(&phy_copy, prbs_flag, &prbs_enabled)); 2164 /* enable tx prbs if not enabled */ 2165 prbs_config.invert = 0; 2166 2167 if ((!prbs_enabled) || follower_prbs_resend) { 2168 for (i = 0; i < num_lane; i++) { 2169 phy_copy.access.lane_mask = 1 << (port_index + i); 2170 if (active_lane_map & 1 << (port_index + i)) { 2171 /* if active lane, use prbspoly13 */ 2172 prbs_config.poly = phymodPrbsPoly13; 2173 } else { 2174 /* if inactive lane, use prbspoly31 */ 2175 prbs_config.poly = phymodPrbsPoly31; 2176 } 2177 /* enable prbs on a per lane basis */ 2178 _SOC_IF_ERR_EXIT 2179 (phymod_phy_prbs_config_set(&phy_copy, prbs_flag, &prbs_config)); 2180 _SOC_IF_ERR_EXIT 2181 (phymod_phy_prbs_enable_set(&phy_copy, prbs_flag, 1)); 2182 /* set tx_disable and pmd lane reset override enable */ 2183 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_copy, phymodPMDTxDisable, 1, 0)); 2184 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_copy, phymodPMDLaneReset, 1, 1)); 2185 } 2186 /* next check if initiator */ 2187 if (is_initiator) { 2188 prbs_flag = 0; 2189 prbs_config.invert = 0; 2190 prbs_config.poly = phymodPrbsPoly13; 2191 PHYMOD_PRBS_DIRECTION_RX_SET(prbs_flag); 2192 _SOC_IF_ERR_EXIT 2193 (phymod_phy_prbs_config_set(&phy_access, prbs_flag, &prbs_config)); 2194 _SOC_IF_ERR_EXIT 2195 (phymod_phy_prbs_enable_set(&phy_access, prbs_flag, 1)); 2196 } 2197 } 2198 } 2199 2200 /* next check prbs rx status if initiator */ 2201 if ((is_initiator) && (!pcs_is_reconfigured)) { 2202 prbs_active_lane_num = 0; 2203 prbs_active_lane_map = 0x0; 2204 for (i = 0; i < num_lane; i++) { 2205 phy_copy.access.lane_mask = 1 << (port_index + i); 2206 /*first read clear the status */ 2207 _SOC_IF_ERR_EXIT 2208 (phymod_phy_prbs_status_get(&phy_copy, 0, &prbs_status)); 2209 sal_usleep(500); 2210 /* first read clear the status */ 2211 _SOC_IF_ERR_EXIT 2212 (phymod_phy_prbs_status_get(&phy_copy, 0, &prbs_status)); 2213 /* next check the lock status */ 2214 if (prbs_status.prbs_lock) { 2215 prbs_active_lane_num++; 2216 prbs_active_lane_map |= 1 << (i + port_index); 2217 } 2218 } 2219 } 2220 2221 /* next check the prbs active lane map if initiator*/ 2222 if ((is_initiator) && (prbs_active_lane_map == active_lane_map) && (!pcs_is_reconfigured)) { 2223 need_reconfig_pcs = 1; 2224 } else if ((!is_initiator) && (!pcs_is_reconfigured) && (!follower_prbs_resend)) { 2225 need_reconfig_pcs = 1; 2226 } 2227 2228 /* check pcs needs to be re-configured if it's no re-congiured already */ 2229 if (need_reconfig_pcs) { 2230 phymod_fec_type_t fec_type; 2231 /* need to reconfigure the pcs */ 2232 /* first disable pcs of the port */ 2233 phy_copy.access.lane_mask = 1 << port_index; 2234 _SOC_IF_ERR_EXIT 2235 (phymod_phy_pcs_enable_set(&phy_access, 0)); 2236 /*set the rx lock and sig detection override */ 2237 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDRxLock, 1, 1)); 2238 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDSignalDetect, 1, 1)); 2239 2240 /* need to adjust the pcs lane swap */ 2241 _SOC_IF_ERR_EXIT 2242 (phymod_phy_pcs_lane_swap_adjust(&phy_access, active_lane_map, txLaneSwap, rxLaneSwap)); 2243 2244 /*then disablethe rx lock and sig detection override */ 2245 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDRxLock, 0, 0)); 2246 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDSignalDetect, 0, 0)); 2247 2248 /* then load the speed id based on the active lane num */ 2249 if ((active_lane_num == 4) || (active_lane_num == 8)) { 2250 fec_type = FecType; 2251 } else { 2252 /* for all the reduced lane speed, only 544_2xn is valid */ 2253 fec_type = phymod_fec_RS544_2XN; 2254 } 2255 _SOC_IF_ERR_EXIT 2256 (phymod_phy_load_speed_id_entry(&phy_access, 50000 * active_lane_num, active_lane_num, fec_type)); 2257 2258 /* next re-enable pcs */ 2259 phy_copy.access.lane_mask = 1 << port_index; 2260 _SOC_IF_ERR_EXIT 2261 (phymod_phy_pcs_enable_set(&phy_access, 1)); 2262 /* set the warm boot variable */ 2263 pcs_is_reconfigured = TRUE; 2264 } 2265 2266 if (is_initiator && need_reconfig_pcs) { 2267 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_LI; 2268 } else if (!is_initiator) { 2269 /* for follower, need to check LI status */ 2270 uint32 li_status = 0; 2271 _SOC_IF_ERR_EXIT 2272 (cdmac_link_interruption_live_status_get(unit, port, &li_status)); 2273 if (li_status) { 2274 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_LI; 2275 } 2276 } 2277 break; 2278 } 2279 case PORTMOD_PORT_RLM_SEND_IDLE: 2280 { 2281 uint32 li_enable, li_status, reg_val; 2282 int local_fault_status, remote_fault_status; 2283 2284 state_string ="SEND_ILDE"; 2285 2286 /* first check if LI is enabled or not */ 2287 _SOC_IF_ERR_EXIT 2288 (cdmac_link_interrupt_ordered_set_enable_get(unit, port, &li_enable)); 2289 /* disable LI if LI is enabled */ 2290 if (li_enable) { 2291 _SOC_IF_ERR_EXIT 2292 (cdmac_link_interrupt_ordered_set_enable(unit, port, 0)); 2293 } 2294 /* next check idles are valid */ 2295 _SOC_IF_ERR_EXIT(READ_CDMAC_RX_LSS_STATUSr(unit, port, ®_val)); 2296 li_status = soc_reg_field_get(unit, CDMAC_RX_LSS_STATUSr, reg_val, LINK_INTERRUPTION_LIVE_STATUSf); 2297 local_fault_status = soc_reg_field_get(unit, CDMAC_RX_LSS_STATUSr, reg_val, LOCAL_FAULT_STATUSf); 2298 remote_fault_status = soc_reg_field_get(unit, CDMAC_RX_LSS_STATUSr, reg_val, REMOTE_FAULT_STATUSf); 2299 /* idle is valid only if none of the above three status are 0 */ 2300 if( (!li_status && !local_fault_status && !remote_fault_status) || 2301 (!is_initiator) ) { 2302 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_DONE; 2303 /* clear tx stall */ 2304 _SOC_IF_ERR_EXIT 2305 (cdmac_tx_stall_enable_set(unit, port, 0)); 2306 } 2307 break; 2308 } 2309 case PORTMOD_PORT_RLM_ERROR: 2310 state_string ="ERROR"; 2311 *is_done = 1; 2312 break; 2313 case PORTMOD_PORT_RLM_DONE: 2314 state_string ="DONE"; 2315 *is_done = 1; 2316 /* do nothing */ 2317 break; 2318 default: 2319 *is_done = 1; 2320 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 2321 (_SOC_MSG("RLM state not supported \n"))); 2322 break; 2323 } 2324 } 2325 2326 /* finally restore all the Warm boot variables */ 2327 _SOC_IF_ERR_EXIT 2328 (PM8x50_INITIATOR_SET(unit, pm_info, is_initiator, port_index)); 2329 2330 _SOC_IF_ERR_EXIT 2331 (PM8x50_PCS_RECONFIG_SET(unit, pm_info, pcs_is_reconfigured, port_index)); 2332 2333 _SOC_IF_ERR_EXIT 2334 (PM8x50_ACTIVE_LANE_MAP_SET(unit, pm_info, active_lane_map, port_index)); 2335 2336 _SOC_IF_ERR_EXIT 2337 (PM8x50_RLM_STATE_SET(unit, pm_info, local_port_rlm_state.rlm_state, port_index)); 2338 2339 LOG_VERBOSE(BSL_LS_SOC_PHY, 2340 (BSL_META_U(unit, 2341 "port %d RLM state is %-23s \n"), 2342 port, state_string)); 2343 2344 exit: 2345 SOC_FUNC_RETURN; 2346 } 2347 2348 2349 static int pm8x50_periodic_callback(int unit, int port) 2350 { 2351 pm_info_t pm_info; 2352 int port_index, rlm_enabled, rlm_state, is_400g_an, an_400g_state; 2353 uint32 bitmap; 2354 int rlm_done = 1, an_done = 1; 2355 2356 SOC_INIT_FUNC_DEFS; 2357 2358 2359 _SOC_IF_ERR_EXIT(portmod_pm_info_get(unit, port, &pm_info)); 2360 2361 /* LOG_ERROR(BSL_LS_SOC_PORT, 2362 (BSL_META_U(unit, "Callback was called port=%d\n"), port)); */ 2363 2364 /* get port index */ 2365 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 2366 2367 /* first get all the RLM warmboot variable */ 2368 _SOC_IF_ERR_EXIT 2369 (PM8x50_RLM_ENABLE_GET(unit, pm_info, &rlm_enabled, port_index)); 2370 2371 _SOC_IF_ERR_EXIT 2372 (PM8x50_RLM_STATE_GET(unit, pm_info, &rlm_state, port_index)); 2373 2374 /* read the 400G an enabled */ 2375 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_GET(unit, pm_info, &is_400g_an, port_index)); 2376 2377 /* check if RLM state machine needs to be updated */ 2378 if (rlm_enabled == 1) { 2379 /*next check only state is not done or error */ 2380 if ((rlm_state != PORTMOD_PORT_RLM_DONE) && (rlm_state != PORTMOD_PORT_RLM_ERROR)) { 2381 _SOC_IF_ERR_EXIT(pm8x50_port_rlm_state_update(unit, port, pm_info, &rlm_done)); 2382 } 2383 } 2384 2385 /* check if 400G an state machine needs to be updated */ 2386 if (is_400g_an) { 2387 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_GET(unit, pm_info, &an_400g_state)); 2388 if (an_400g_state < PM8X50_PORT_AN_COMPLETE) { 2389 _SOC_IF_ERR_EXIT(_pm8x50_400g_an_workaround(unit, port, pm_info, &an_done)); 2390 } 2391 } 2392 2393 /* if both signal unregister - go for it */ 2394 if (rlm_done && an_done) { 2395 _SOC_IF_ERR_EXIT(portmod_port_periodic_callback_unregister(unit, port)); 2396 } 2397 2398 2399 exit: 2400 SOC_FUNC_RETURN; 2401 } 2402 2403 2404 /*Add new pm.*/ 2405 int pm8x50_pm_init(int unit, 2406 const portmod_pm_create_info_internal_t* pm_add_info, 2407 int wb_buffer_index, 2408 pm_info_t pm_info) 2409 { 2410 const portmod_pm8x50_create_info_t *info = 2411 &pm_add_info->pm_specific_info.pm8x50; 2412 pm8x50_t pm8x50_data = NULL; 2413 int i, rv; 2414 int pm_is_active, ts_enable_port_count, is_initiator, pcs_reconfigured, active_lane_map; 2415 int is_core_initialized, fec, invalid_port, rlm_state, fecType, txLaneMap, rxLaneMap, rlm_enabled; 2416 int an_state, is_400g_an, an_wait_link_count, is_ber_war_enable = 0, ber_war_state = 0, ber_war_wait_count = 0; 2417 int core_is_flexe_configured, remote_pause; 2418 uint8 ovco_pll_adv_lane_bitmap, tvco_pll_adv_lane_bitmap; 2419 uint8 ovco_pll_active_lane_bitmap, tvco_pll_active_lane_bitmap; 2420 int probe= 0; 2421 uint32_t pll_div; 2422 phymod_phy_access_t phy_access; 2423 portmod_vco_type_t vco; 2424 int phy; 2425 SOC_INIT_FUNC_DEFS; 2426 2427 pm_info->type = pm_add_info->type; 2428 pm_info->unit = unit; 2429 pm_info->wb_buffer_id = wb_buffer_index; 2430 2431 /* PM8x50 specific info */ 2432 pm8x50_data = sal_alloc(sizeof(struct pm8x50_s), "specific_db"); 2433 SOC_NULL_CHECK(pm8x50_data); 2434 pm_info->pm_data.pm8x50_db = pm8x50_data; 2435 2436 PORTMOD_PBMP_ASSIGN(pm8x50_data->phys, pm_add_info->phys); 2437 pm8x50_data->int_core_access.type = phymodDispatchTypeCount; 2438 PORTMOD_PBMP_ITER(pm_add_info->phys, phy) { 2439 PM_8x50_INFO(pm_info)->first_phy = phy; 2440 break; 2441 } 2442 pm8x50_data->warmboot_skip_db_restore = TRUE; 2443 pm8x50_data->rescal = info->rescal; 2444 pm8x50_data->portmod_mac_soft_reset = info->portmod_mac_soft_reset; 2445 pm8x50_data->portmod_egress_buffer_reset = info->portmod_egress_buffer_reset; 2446 2447 /* init intertnal SerDes core access */ 2448 phymod_core_access_t_init(&pm8x50_data->int_core_access); 2449 2450 sal_memcpy(&pm8x50_data->polarity, &info->polarity, 2451 sizeof(phymod_polarity_t)); 2452 sal_memcpy(&(pm8x50_data->int_core_access.access), &info->access.access, 2453 sizeof(phymod_access_t)); 2454 2455 sal_memcpy(&pm8x50_data->lane_map, &info->lane_map, 2456 sizeof(pm8x50_data->lane_map)); 2457 pm8x50_data->ref_clk = info->ref_clk; 2458 pm8x50_data->fw_load_method = info->fw_load_method; 2459 pm8x50_data->external_fw_loader = info->external_fw_loader; 2460 pm8x50_data->tvco = info->tvco; 2461 pm8x50_data->ovco = info->ovco; 2462 pm8x50_data->core_num = info->core_num; 2463 pm8x50_data->afe_pll = info->afe_pll; 2464 pm8x50_data->is_master_pm = info->is_master_pm; 2465 pm8x50_data->allow_20p625g_tvco = info->allow_20p625g_tvco; 2466 2467 if (info->access.access.bus == NULL) { 2468 /* if null - use default */ 2469 pm8x50_data->int_core_access.access.bus = &pm8x50_default_bus; 2470 } else { 2471 /* check null for mem_read/mem_write */ 2472 if (pm8x50_data->int_core_access.access.bus->mem_read == NULL) { 2473 pm8x50_data->int_core_access.access.bus->mem_read =pm8x50_default_bus.mem_read; 2474 } 2475 if (pm8x50_data->int_core_access.access.bus->mem_write == NULL) { 2476 pm8x50_data->int_core_access.access.bus->mem_write =pm8x50_default_bus.mem_write; 2477 } 2478 } 2479 2480 if (pm8x50_data->external_fw_loader == NULL) { 2481 /* if null - use default */ 2482 pm8x50_data->external_fw_loader = pm8x50_default_fw_loader; 2483 } 2484 2485 /*init wb buffer*/ 2486 _SOC_IF_ERR_EXIT(pm8x50_wb_buffer_init(unit, wb_buffer_index, pm_info)); 2487 2488 2489 if (pm8x50_data->int_core_access.access.pmd_info_ptr == NULL) { 2490 pm8x50_data->int_core_access.access.pmd_info_ptr = sal_alloc(PMD_INFO_DATA_STRUCTURE_SIZE, 2491 "PortMod PM PMD info"); 2492 if (pm8x50_data->int_core_access.access.pmd_info_ptr == NULL) { 2493 return SOC_E_MEMORY; 2494 } 2495 sal_memset(pm8x50_data->int_core_access.access.pmd_info_ptr, 0, PMD_INFO_DATA_STRUCTURE_SIZE); 2496 } 2497 2498 2499 if (SOC_WARM_BOOT(unit)) { 2500 int rlm_enabled, rlm_state, i, port_local; 2501 /* For warmboot, probe Serdes driver type for active PMs. */ 2502 is_core_initialized = 0; 2503 rlm_enabled = 0; 2504 rlm_state = PORTMOD_PORT_RLM_FSM_COUNT; 2505 rv = PM8x50_IS_CORE_INITIALIZED_GET(unit, pm_info, &is_core_initialized); 2506 _SOC_IF_ERR_EXIT(rv); 2507 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_GET(unit, pm_info, &an_state)); 2508 2509 /* next check if RLM portmod thread needs to be re-registered */ 2510 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2511 /* first get the logical port id */ 2512 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info,i, &port_local)); 2513 _SOC_IF_ERR_EXIT(PM8x50_RLM_ENABLE_GET(unit, pm_info, &rlm_enabled, i)); 2514 _SOC_IF_ERR_EXIT(PM8x50_RLM_STATE_GET(unit, pm_info, &rlm_state, i)); 2515 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_GET(unit, pm_info, &is_400g_an, i)); 2516 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_REMOTE_PAUSE_GET(unit, pm_info, &remote_pause, i)); 2517 /* need to re-register the call back */ 2518 if ( (port_local >= 0) && (((rlm_enabled) && (rlm_state >= PORTMOD_PORT_RLM_SEND_PACKET_DATA) && 2519 (rlm_state < PORTMOD_PORT_RLM_DONE)) || 2520 ((is_400g_an) && (an_state < PM8X50_PORT_AN_COMPLETE))) ) { 2521 _SOC_IF_ERR_EXIT(portmod_port_periodic_callback_register(unit, port_local, pm8x50_periodic_callback, PORTMOD_THREAD_INTERVAL_1s)); 2522 } 2523 } 2524 2525 if (is_core_initialized) { 2526 _SOC_IF_ERR_EXIT(portmod_common_serdes_probe(pm8x50_serdes_list, &pm8x50_data->int_core_access, &probe)); 2527 if (!probe) { 2528 LOG_ERROR(BSL_LS_SOC_PORT, 2529 (BSL_META_U(unit, "ERROR: serdes probe failed type=%d\n"), pm8x50_data->int_core_access.type)); 2530 } 2531 2532 /* Get VCO rates from HW */ 2533 sal_memcpy(&phy_access, &(pm8x50_data->int_core_access), 2534 sizeof(phymod_phy_access_t)); 2535 2536 /* 1. Get TVCO rate */ 2537 phy_access.access.pll_idx = phy_access.access.tvco_pll_index; 2538 _SOC_IF_ERR_EXIT(phymod_phy_pll_multiplier_get(&phy_access, &pll_div)); 2539 _SOC_IF_ERR_EXIT(_pm8x50_pll_to_vco_get(info->ref_clk, pll_div, &vco)); 2540 pm8x50_data->tvco = vco; 2541 /* 2. Get OVCO rate: 2542 * a. If OVCO is not free, get OVCO rate from HW. 2543 * b. If OVCO is free, OVCO is powerdown. 2544 */ 2545 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_active_lane_bitmap)); 2546 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_adv_lane_bitmap)); 2547 if (ovco_pll_active_lane_bitmap | ovco_pll_adv_lane_bitmap) { 2548 phy_access.access.pll_idx = (phy_access.access.tvco_pll_index == 1)? 0: 1; 2549 _SOC_IF_ERR_EXIT(phymod_phy_pll_multiplier_get(&phy_access, &pll_div)); 2550 _SOC_IF_ERR_EXIT(_pm8x50_pll_to_vco_get(info->ref_clk, pll_div, &vco)); 2551 pm8x50_data->ovco = vco; 2552 } else { 2553 pm8x50_data->ovco = portmodVCOInvalid; 2554 } 2555 } 2556 } else { 2557 /* For coldboot, initialized warmboot variables for the PM. */ 2558 is_core_initialized = 0; 2559 rv = PM8x50_IS_CORE_INITIALIZED_SET(unit, pm_info, 2560 is_core_initialized); 2561 _SOC_IF_ERR_EXIT(rv); 2562 2563 pm_is_active = 0; 2564 rv = PM8x50_IS_ACTIVE_SET(unit, pm_info, pm_is_active); 2565 _SOC_IF_ERR_EXIT(rv); 2566 2567 ovco_pll_adv_lane_bitmap = 0; 2568 rv = PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, ovco_pll_adv_lane_bitmap); 2569 _SOC_IF_ERR_EXIT(rv); 2570 2571 tvco_pll_adv_lane_bitmap = 0; 2572 rv = PM8x50_TVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, tvco_pll_adv_lane_bitmap); 2573 _SOC_IF_ERR_EXIT(rv); 2574 2575 ovco_pll_active_lane_bitmap = 0; 2576 rv = PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, ovco_pll_active_lane_bitmap); 2577 _SOC_IF_ERR_EXIT(rv); 2578 2579 tvco_pll_active_lane_bitmap = 0; 2580 rv = PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, tvco_pll_active_lane_bitmap); 2581 _SOC_IF_ERR_EXIT(rv); 2582 2583 fec = 0; 2584 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2585 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, fec)); 2586 } 2587 2588 invalid_port = -1; 2589 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2590 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_SET(unit, pm_info, i, invalid_port)); 2591 } 2592 2593 ts_enable_port_count = 0; 2594 rv = PM8x50_TS_ENABLE_PORT_COUNT_SET(unit, pm_info, ts_enable_port_count); 2595 _SOC_IF_ERR_EXIT(rv); 2596 2597 rlm_enabled = 0; 2598 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2599 _SOC_IF_ERR_EXIT(PM8x50_RLM_ENABLE_SET(unit, pm_info, rlm_enabled, i)); 2600 } 2601 2602 is_initiator = 0; 2603 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2604 _SOC_IF_ERR_EXIT(PM8x50_INITIATOR_SET(unit, pm_info, is_initiator, i)); 2605 } 2606 2607 pcs_reconfigured = 0; 2608 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2609 _SOC_IF_ERR_EXIT(PM8x50_PCS_RECONFIG_SET(unit, pm_info, pcs_reconfigured, i)); 2610 } 2611 2612 active_lane_map = 0; 2613 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2614 _SOC_IF_ERR_EXIT(PM8x50_ACTIVE_LANE_MAP_SET(unit, pm_info, active_lane_map, i)); 2615 } 2616 2617 rlm_state = PORTMOD_PORT_RLM_FSM_COUNT; 2618 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2619 _SOC_IF_ERR_EXIT(PM8x50_RLM_STATE_SET(unit, pm_info, rlm_state, i)); 2620 } 2621 2622 fecType = 0; 2623 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2624 _SOC_IF_ERR_EXIT(PM8x50_ORIGINAL_FEC_SET(unit, pm_info, fecType, i)); 2625 } 2626 2627 txLaneMap = 0x76543210; 2628 rv = PM8x50_ORIG_TX_LANE_MAP_SET(unit, pm_info, txLaneMap); 2629 _SOC_IF_ERR_EXIT(rv); 2630 2631 rxLaneMap = 0x76543210; 2632 rv = PM8x50_ORIG_RX_LANE_MAP_SET(unit, pm_info, rxLaneMap); 2633 _SOC_IF_ERR_EXIT(rv); 2634 2635 is_400g_an = 0; 2636 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2637 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_SET(unit, pm_info, is_400g_an, i)); 2638 } 2639 2640 an_state = PM8X50_PORT_AN_STATE_COUNT; 2641 rv = PM8x50_400G_AN_STATE_SET(unit, pm_info, an_state); 2642 _SOC_IF_ERR_EXIT(rv); 2643 2644 an_wait_link_count = 0; 2645 rv = PM8x50_400G_AN_WAIT_LINK_COUNT_SET(unit, pm_info, an_wait_link_count); 2646 _SOC_IF_ERR_EXIT(rv); 2647 2648 is_ber_war_enable = 0; 2649 ber_war_state = PM8X50_PORT_BER_WAR_STATE_COUNT; 2650 ber_war_wait_count = 0; 2651 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2652 _SOC_IF_ERR_EXIT(PM8x50_BER_WAR_ENABLE_SET(unit, pm_info, is_ber_war_enable, i)); 2653 2654 rv = PM8x50_BER_WAR_STATE_SET(unit, pm_info, ber_war_state, i); 2655 _SOC_IF_ERR_EXIT(rv); 2656 2657 rv = PM8x50_BER_WAR_WAIT_COUNT_SET(unit, pm_info, ber_war_wait_count, i); 2658 _SOC_IF_ERR_EXIT(rv); 2659 } 2660 2661 core_is_flexe_configured = 0; 2662 rv = PM8x50_IS_CORE_FLEXE_CONFIGURED_SET(unit, pm_info, core_is_flexe_configured); 2663 _SOC_IF_ERR_EXIT(rv); 2664 2665 remote_pause = 0; 2666 for (i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 2667 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_REMOTE_PAUSE_SET(unit, pm_info, remote_pause, i)); 2668 } 2669 } 2670 2671 exit: 2672 if (SOC_FUNC_ERROR) { 2673 pm8x50_pm_destroy(unit, pm_info); 2674 } 2675 SOC_FUNC_RETURN; 2676 } 2677 2678 /*Release PM resources*/ 2679 int pm8x50_pm_destroy(int unit, pm_info_t pm_info) 2680 { 2681 SOC_INIT_FUNC_DEFS; 2682 2683 if (pm_info->pm_data.pm8x50_db != NULL) { 2684 if (PM_8x50_INFO(pm_info)->int_core_access.access.pmd_info_ptr != NULL) { 2685 sal_free(PM_8x50_INFO(pm_info)->int_core_access.access.pmd_info_ptr); 2686 PM_8x50_INFO(pm_info)->int_core_access.access.pmd_info_ptr = NULL; 2687 } 2688 sal_free(pm_info->pm_data.pm8x50_db); 2689 pm_info->pm_data.pm8x50_db = NULL; 2690 } 2691 2692 SOC_FUNC_RETURN; 2693 } 2694 2695 /* This function will check the speed config is valid or not, and return required vco for valid input */ 2696 /* The supported speed config in this function is based on PM8x50 Portmod Spec */ 2697 STATIC 2698 int _pm8x50_port_speed_config_to_vco_get(const portmod_speed_config_t* speed_config, 2699 int speed_for_pcs_bypass_port, 2700 portmod_vco_type_t* vco) 2701 { 2702 SOC_INIT_FUNC_DEFS; 2703 2704 if (!speed_for_pcs_bypass_port) { 2705 _SOC_IF_ERR_EXIT( 2706 _pm8x50_fs_ability_table_vco_get(speed_config->speed, 2707 speed_config->num_lane, 2708 speed_config->fec, 2709 vco)); 2710 } else { 2711 _SOC_IF_ERR_EXIT( 2712 pm8x50_shared_pcs_bypassed_vco_get(speed_config->speed, vco)); 2713 } 2714 /* 2715 * when *vco == portmodVCOInvalid, it means the entered combination of 2716 * port speed, number of lanes, and FEC type is not supported. 2717 */ 2718 if (*vco == portmodVCOInvalid) { 2719 return SOC_E_CONFIG; 2720 } 2721 2722 exit: 2723 SOC_FUNC_RETURN; 2724 } 2725 2726 /* This function can be called before port is attached. 2727 * So we need to use physical port number to access the register. 2728 */ 2729 STATIC 2730 int _pm8x50_pm_version_get(int unit, pm_info_t pm_info, pm_version_t *version) 2731 { 2732 uint32 reg_val, tech_process; 2733 int phy_acc; 2734 2735 SOC_INIT_FUNC_DEFS; 2736 2737 version->type = PM_TYPE_PM8X50; 2738 version->gen = PM_GEN_INVALID; 2739 version->tech_process = PM_TECH_INVALID; 2740 version->revision_number = PM_REVISION_NUM_INVALID; 2741 version->revision_letter = PM_REVISION_LETTER_INVALID; 2742 2743 phy_acc = PM_8x50_INFO(pm_info)->first_phy | SOC_REG_ADDR_PHY_ACC_MASK; 2744 2745 _SOC_IF_ERR_EXIT(READ_CDPORT_PM_VERSION_IDr(unit, phy_acc, ®_val)); 2746 2747 tech_process = soc_reg_field_get(unit, CDPORT_PM_VERSION_IDr, reg_val, TECH_PROCESSf); 2748 if (tech_process == 1) { 2749 version->tech_process = PM_TECH_16NM; 2750 } 2751 2752 exit: 2753 SOC_FUNC_RETURN; 2754 } 2755 2756 STATIC 2757 int _pm8x50_lanebitmap_set(int starting_lane, int num_lane, uint8 *bitmap) 2758 { 2759 int i; 2760 2761 for (i = 0; i < num_lane; i++) { 2762 *bitmap |= 1 << (starting_lane + i); 2763 } 2764 2765 return SOC_E_NONE; 2766 } 2767 2768 /* This function is to validate the FEC settings on each PM. 2769 * For each MPP, we can not support both RS544 and RS272. 2770 * On 16nm, we can also not support both RS528 and RS272 on the same MPP. 2771 */ 2772 STATIC 2773 int _pm8x50_fec_validate(int unit, 2774 uint32 flags, 2775 uint8 rs528_bitmap, 2776 uint8 rs544_bitmap, 2777 uint8 rs272_bitmap, 2778 uint8 *affected_lane_bitmap) 2779 { 2780 uint8 rs_fec_mpp0, rs_fec_mpp1, rs272_mpp0, rs272_mpp1; 2781 SOC_INIT_FUNC_DEFS; 2782 2783 /* rs_fec_mpp0, rs_fec_mpp1 contains lane bitmap for 2784 * the RS FECs which can not co-exist with RS272. 2785 * For 16nm, rsfec contains bitmap for both RS544 and RS528. 2786 * For 7nm, rsfec contains bitmap for RS544 only. 2787 */ 2788 if (PM8X50_PM_VERSION_F_REV0_16NM_GET(flags)) { 2789 rs_fec_mpp0 = (rs528_bitmap | rs544_bitmap) & 0xf; 2790 rs_fec_mpp1 = (rs528_bitmap | rs544_bitmap) & 0xf0; 2791 } else { 2792 rs_fec_mpp0 = rs544_bitmap & 0xf; 2793 rs_fec_mpp1 = rs544_bitmap & 0xf0; 2794 } 2795 rs272_mpp0 = rs272_bitmap & 0xf; 2796 rs272_mpp1 = rs272_bitmap & 0xf0; 2797 *affected_lane_bitmap = 0; 2798 2799 if (rs_fec_mpp0 && rs272_mpp0) { 2800 *affected_lane_bitmap = rs_fec_mpp0 | rs272_mpp0; 2801 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 2802 (_SOC_MSG("Can not accommodate FEC settings on MPP0."))); 2803 2804 } else if (rs_fec_mpp1 && rs272_mpp1) { 2805 *affected_lane_bitmap = rs_fec_mpp1 | rs272_mpp1; 2806 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 2807 (_SOC_MSG("Can not accommodate FEC settings on MPP1."))); 2808 } 2809 2810 exit: 2811 SOC_FUNC_RETURN; 2812 } 2813 2814 /*Get the suggested VCO values based on the speed config list*/ 2815 int pm8x50_pm_vcos_get(int unit, 2816 portmod_dispatch_type_t pm_type, 2817 uint32 flags, 2818 portmod_pm_vco_setting_t* vco_select) 2819 { 2820 pm8x50_vcos_bmp_t vcos = 0, vco_bmp = 0; 2821 portmod_vco_type_t current_tvco, current_ovco; 2822 uint8_t rs528_bm = 0, rs544_bm = 0, rs272_bm = 0, affected_bm = 0; 2823 portmod_vco_type_t vco; 2824 int i, rv = 0; 2825 int is_pcs_bypass; 2826 uint32 fec_flags = 0, vcos_flags = 0; 2827 2828 SOC_INIT_FUNC_DEFS; 2829 2830 if(vco_select == NULL){ 2831 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 2832 (_SOC_MSG("vco_select NULL paramaeter"))); 2833 } 2834 2835 for (i = 0; i < vco_select->num_speeds; i++) { 2836 vco = portmodVCOInvalid; 2837 rv = _pm8x50_port_speed_config_to_vco_get(&(vco_select->speed_config_list[i]), 2838 vco_select->speed_for_pcs_bypass_port[i], &vco); 2839 if (rv == SOC_E_CONFIG) { 2840 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 2841 (_SOC_MSG("Speed config is not supported"))); 2842 } 2843 is_pcs_bypass = vco_select->speed_for_pcs_bypass_port[i]; 2844 _SOC_IF_ERR_EXIT(_pm8x50_required_vco_bitmap_get(unit, vco, is_pcs_bypass, &vco_bmp)); 2845 vcos |= vco_bmp; 2846 2847 if ((vco_select->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_272) || 2848 (vco_select->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_272_2XN)) { 2849 _SOC_IF_ERR_EXIT(_pm8x50_lanebitmap_set(vco_select->port_starting_lane_list[i], 2850 vco_select->speed_config_list[i].num_lane, 2851 &rs272_bm)); 2852 } else if ((vco_select->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_544) || 2853 (vco_select->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_544_2XN)) { 2854 _SOC_IF_ERR_EXIT(_pm8x50_lanebitmap_set(vco_select->port_starting_lane_list[i], 2855 vco_select->speed_config_list[i].num_lane, 2856 &rs544_bm)); 2857 } else if (vco_select->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_FEC) { 2858 _SOC_IF_ERR_EXIT(_pm8x50_lanebitmap_set(vco_select->port_starting_lane_list[i], 2859 vco_select->speed_config_list[i].num_lane, 2860 &rs528_bm)); 2861 } 2862 } 2863 2864 /* Validate FEC settings for RS528, RS544 and RS272 */ 2865 if (PORTMOD_PM8X50_REV0_16NM_GET(flags)) { 2866 PM8X50_PM_VERSION_F_REV0_16NM_SET(fec_flags); 2867 } 2868 _SOC_IF_ERR_EXIT(_pm8x50_fec_validate(unit, 2869 fec_flags, 2870 rs528_bm, 2871 rs544_bm, 2872 rs272_bm, 2873 &affected_bm)); 2874 2875 current_tvco = portmodVCOInvalid; 2876 current_ovco = portmodVCOInvalid; 2877 2878 if (PORTMOD_ALLOW_20P625G_TVCO_GET(flags)) { 2879 PM8X50_TVCO_SUPPORT_20P625G_SET(vcos_flags); 2880 } 2881 2882 /* Try to allocate required VCOs */ 2883 _SOC_IF_ERR_EXIT( 2884 pm8x50_vcos_request_allocate(unit, vcos_flags, vcos, ¤t_tvco, ¤t_ovco)); 2885 2886 /* Set Output */ 2887 vco_select->tvco = current_tvco; 2888 vco_select->ovco = current_ovco; 2889 vco_select->is_tvco_new = (current_tvco == portmodVCOInvalid) ? 0 : 1; 2890 vco_select->is_ovco_new = (current_ovco == portmodVCOInvalid) ? 0 : 1; 2891 2892 exit: 2893 SOC_FUNC_RETURN; 2894 } 2895 2896 STATIC 2897 int _pm8x50_port_tsc_reset_set(int unit, pm_info_t pm_info, int phy_acc, int tvco_pll_index, int in_reset) 2898 { 2899 uint32 reg_val; 2900 SOC_INIT_FUNC_DEFS; 2901 2902 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_CTRL_REGr(unit, phy_acc, ®_val)); 2903 soc_reg_field_set(unit, CDPORT_XGXS0_CTRL_REGr, ®_val, TSC_CLK_SELf, tvco_pll_index); 2904 2905 /* 2906 * in_reset == 1: 2907 * 1. Power down TSC. 2908 * 2. Put TSC into RST for slave cores. 2909 * in_reset == 0: 2910 * 1. Power up TSC. 2911 * 2. Toggle TSC RST bit. 2912 */ 2913 if (in_reset) { 2914 int is_core_initialized = 0; 2915 soc_reg_field_set(unit, CDPORT_XGXS0_CTRL_REGr, ®_val, TSC_PWRDWNf, 1); 2916 if (!(PM_8x50_INFO(pm_info)->is_master_pm)) { 2917 /* Put TSC into reset for slave PMs */ 2918 soc_reg_field_set(unit, CDPORT_XGXS0_CTRL_REGr, ®_val, TSC_RSTBf, 0); 2919 } 2920 _SOC_IF_ERR_EXIT(WRITE_CDPORT_XGXS0_CTRL_REGr(unit, phy_acc, reg_val)); 2921 2922 /* clear the warm boot variable */ 2923 _SOC_IF_ERR_EXIT(PM8x50_IS_CORE_INITIALIZED_SET(unit, pm_info, is_core_initialized)); 2924 } else { 2925 soc_reg_field_set(unit, CDPORT_XGXS0_CTRL_REGr, ®_val, TSC_PWRDWNf, 1); 2926 soc_reg_field_set(unit, CDPORT_XGXS0_CTRL_REGr, ®_val, TSC_RSTBf, 0); 2927 _SOC_IF_ERR_EXIT(WRITE_CDPORT_XGXS0_CTRL_REGr(unit, phy_acc, reg_val)); 2928 2929 soc_reg_field_set(unit, CDPORT_XGXS0_CTRL_REGr, ®_val, TSC_PWRDWNf, 0); 2930 soc_reg_field_set(unit, CDPORT_XGXS0_CTRL_REGr, ®_val, TSC_RSTBf, 1); 2931 _SOC_IF_ERR_EXIT(WRITE_CDPORT_XGXS0_CTRL_REGr(unit, phy_acc, reg_val)); 2932 } 2933 2934 2935 /* Based on the feedback from SJ pmd support team, ~10-15usecs would be sufficient 2936 * for the PLL/AFE to settle down out of IDDQ reset. 2937 */ 2938 sal_usleep(10); 2939 2940 exit: 2941 SOC_FUNC_RETURN; 2942 } 2943 2944 /*Enable port macro.*/ 2945 /* This function contains 3 parts: 2946 * 1. Bring Serdes out of hard reset. 2947 * 2. Bring 2 CDMACs out of hard reset. 2948 */ 2949 int pm8x50_pm_enable(int unit, 2950 int pm_id, 2951 pm_info_t pm_info, 2952 int enable) 2953 { 2954 uint32 reg_val; 2955 int phy_acc; 2956 int is_reset; 2957 int tvco_pll_index; 2958 SOC_INIT_FUNC_DEFS; 2959 2960 /* Get the first physical port of the pm core */ 2961 phy_acc = PM_8x50_INFO(pm_info)->first_phy | SOC_REG_ADDR_PHY_ACC_MASK; 2962 2963 _SOC_IF_ERR_EXIT(READ_CDPORT_MAC_CONTROLr(unit, phy_acc, ®_val)); 2964 is_reset = soc_reg_field_get(unit, CDPORT_MAC_CONTROLr, reg_val, CDMAC0_RESETf); 2965 2966 tvco_pll_index = PM8X50_TVCO_PLL_INDEX_GET(pm_info); 2967 2968 if(enable && is_reset) { 2969 /* Bring Serdes OOR */ 2970 _SOC_IF_ERR_EXIT(_pm8x50_port_tsc_reset_set(unit, pm_info, phy_acc, tvco_pll_index, 0)); 2971 2972 /* Bring MAC OOR */ 2973 _SOC_IF_ERR_EXIT(READ_CDPORT_MAC_CONTROLr(unit, phy_acc, ®_val)); 2974 soc_reg_field_set(unit, CDPORT_MAC_CONTROLr, ®_val, CDMAC0_RESETf, 0); 2975 soc_reg_field_set(unit, CDPORT_MAC_CONTROLr, ®_val, CDMAC1_RESETf, 0); 2976 _SOC_IF_ERR_EXIT(WRITE_CDPORT_MAC_CONTROLr(unit, phy_acc, reg_val)); 2977 } else if ((!enable) && (!is_reset)){ /* disable */ 2978 /* put MAC in reset */ 2979 _SOC_IF_ERR_EXIT(READ_CDPORT_MAC_CONTROLr(unit, phy_acc, ®_val)); 2980 soc_reg_field_set(unit, CDPORT_MAC_CONTROLr, ®_val, CDMAC0_RESETf, 1); 2981 soc_reg_field_set(unit, CDPORT_MAC_CONTROLr, ®_val, CDMAC1_RESETf, 1); 2982 _SOC_IF_ERR_EXIT(WRITE_CDPORT_MAC_CONTROLr(unit, phy_acc, reg_val)); 2983 2984 /* If current PM is not master PM, put Serdes into reset*/ 2985 _SOC_IF_ERR_EXIT(_pm8x50_port_tsc_reset_set(unit, pm_info, phy_acc, tvco_pll_index, 1)); 2986 } 2987 2988 exit: 2989 SOC_FUNC_RETURN; 2990 } 2991 2992 STATIC 2993 int _pm8x50_pm_core_probe(int unit, pm_info_t pm_info, const portmod_port_add_info_t* add_info) 2994 { 2995 int probe =0; 2996 SOC_INIT_FUNC_DEFS; 2997 2998 _SOC_IF_ERR_EXIT(portmod_common_serdes_probe(pm8x50_serdes_list, &PM_8x50_INFO(pm_info)->int_core_access, &probe)); 2999 3000 exit: 3001 SOC_FUNC_RETURN; 3002 } 3003 3004 /* This function will return required pll based on the ref_clk and vco */ 3005 /* For now, assume PM8x50 only support: 3006 VCO: 20.625G, 25.78125G,26.5625G; 3007 Ref_CLK: 156.25M, 312.5M 3008 For any other input, this function will return E_PARAM 3009 */ 3010 STATIC 3011 int _pm8x50_vco_to_pll_get(phymod_ref_clk_t ref_clock, portmod_vco_type_t vco, uint32_t* pll) 3012 { 3013 int rv = SOC_E_NONE; 3014 SOC_INIT_FUNC_DEFS; 3015 3016 switch (vco) { 3017 case portmodVCO20P625G: 3018 if (ref_clock == phymodRefClk156Mhz) { 3019 *pll = phymod_TSCBH_PLL_DIV132; 3020 } else if (ref_clock == phymodRefClk312Mhz) { 3021 *pll = phymod_TSCBH_PLL_DIV66; 3022 } else { 3023 rv = SOC_E_PARAM; 3024 } 3025 break; 3026 case portmodVCO25P781G: 3027 if (ref_clock == phymodRefClk156Mhz) { 3028 *pll = phymod_TSCBH_PLL_DIV165; 3029 } else if (ref_clock == phymodRefClk312Mhz) { 3030 *pll = phymod_TSCBH_PLL_DIV82P5; 3031 } else { 3032 rv = SOC_E_PARAM; 3033 } 3034 break; 3035 case portmodVCO26P562G: 3036 if (ref_clock == phymodRefClk156Mhz) { 3037 *pll = phymod_TSCBH_PLL_DIV170; 3038 } else if (ref_clock == phymodRefClk312Mhz) { 3039 *pll = phymod_TSCBH_PLL_DIV85; 3040 } else { 3041 rv = SOC_E_PARAM; 3042 } 3043 break; 3044 case portmodVCO25G: 3045 if (ref_clock == phymodRefClk156Mhz) { 3046 *pll = phymod_TSCBH_PLL_DIV160; 3047 } else if (ref_clock == phymodRefClk312Mhz) { 3048 *pll = phymod_TSCBH_PLL_DIV80; 3049 } else { 3050 rv = SOC_E_PARAM; 3051 } 3052 break; 3053 case portmodVCO27P343G: 3054 if (ref_clock == phymodRefClk156Mhz) { 3055 *pll = phymod_TSCBH_PLL_DIV175; 3056 } else if (ref_clock == phymodRefClk312Mhz) { 3057 *pll = phymod_TSCBH_PLL_DIV87P5; 3058 } else { 3059 rv = SOC_E_PARAM; 3060 } 3061 break; 3062 case portmodVCO28P125G: 3063 if (ref_clock == phymodRefClk156Mhz) { 3064 *pll = phymod_TSCBH_PLL_DIV180; 3065 } else if (ref_clock == phymodRefClk312Mhz) { 3066 *pll = phymod_TSCBH_PLL_DIV90; 3067 } else { 3068 rv = SOC_E_PARAM; 3069 } 3070 break; 3071 case portmodVCOInvalid: 3072 *pll = phymod_TSCBH_PLL_DIVNONE; 3073 break; 3074 default: 3075 rv = SOC_E_PARAM; 3076 break; 3077 } 3078 _SOC_IF_ERR_EXIT(rv); 3079 3080 exit: 3081 SOC_FUNC_RETURN; 3082 } 3083 3084 STATIC 3085 int _pm8x50_pm_serdes_core_init(int unit, pm_info_t pm_info, const portmod_port_add_info_t* add_info) 3086 { 3087 int rv, tvco_pll_index; 3088 phymod_core_init_config_t core_conf; 3089 phymod_core_status_t core_status; 3090 uint32_t core_is_initialized; 3091 uint32_t init_flags = 0; 3092 uint32_t pll0 = 0, pll1 = 0; 3093 uint32_t tx_lane_map = 0, rx_lane_map = 0, i; 3094 portmod_vco_type_t ovco = 0, tvco = 0; 3095 3096 SOC_INIT_FUNC_DEFS; 3097 3098 rv = PM8x50_IS_CORE_INITIALIZED_GET(unit, pm_info, &core_is_initialized) 3099 _SOC_IF_ERR_EXIT(rv); 3100 3101 _SOC_IF_ERR_EXIT(phymod_core_init_config_t_init(&core_conf)); 3102 tvco_pll_index = PM8X50_TVCO_PLL_INDEX_GET(pm_info); 3103 3104 3105 core_conf.firmware_load_method = PM_8x50_INFO(pm_info)->fw_load_method; 3106 core_conf.firmware_loader = PM_8x50_INFO(pm_info)->external_fw_loader; 3107 core_conf.lane_map = PM_8x50_INFO(pm_info)->lane_map; 3108 core_conf.polarity_map = PM_8x50_INFO(pm_info)->polarity; 3109 3110 /* next translate the lane map into encoded format for RLM usage */ 3111 for (i = 0; i < core_conf.lane_map.num_of_lanes; i++) { 3112 tx_lane_map |= core_conf.lane_map.lane_map_tx[i] << (4 * i); 3113 rx_lane_map |= core_conf.lane_map.lane_map_rx[i] << (4 * i); 3114 } 3115 3116 core_conf.afe_pll.afe_pll_change_default = PM_8x50_INFO(pm_info)->afe_pll.afe_pll_change_default; 3117 core_conf.afe_pll.ams_pll_iqp = PM_8x50_INFO(pm_info)->afe_pll.ams_pll_iqp; 3118 core_conf.afe_pll.ams_pll_en_hrz = PM_8x50_INFO(pm_info)->afe_pll.ams_pll_en_hrz; 3119 3120 _SOC_IF_ERR_EXIT(phymod_phy_inf_config_t_init(&core_conf.interface)); 3121 core_conf.interface.ref_clock = PM_8x50_INFO(pm_info)->ref_clk; 3122 3123 if (PORTMOD_PORT_ADD_F_SKIP_SPEED_INIT_GET(add_info)) { 3124 /* If PORTMOD_PORT_ADD_F_SKIP_SPEED_INIT flag is set, do not bring up PLLs */ 3125 if (!PORTMOD_CORE_INIT_FLAG_INITIALZIED_GET(core_is_initialized)) { 3126 /* Only if core is not initilized - put tvco and ovco as invalid */ 3127 ovco = portmodVCOInvalid; 3128 tvco = portmodVCOInvalid; 3129 PM_8x50_INFO(pm_info)->ovco = ovco; 3130 PM_8x50_INFO(pm_info)->tvco = tvco; 3131 } 3132 } else if ((PM_8x50_INFO(pm_info)->ovco == portmodVCOInvalid) && (PM_8x50_INFO(pm_info)->tvco == portmodVCOInvalid)) { 3133 ovco = add_info->ovco; 3134 tvco = add_info->tvco; 3135 PM_8x50_INFO(pm_info)->ovco = ovco; 3136 PM_8x50_INFO(pm_info)->tvco = tvco; 3137 } else { 3138 ovco = PM_8x50_INFO(pm_info)->ovco; 3139 tvco = PM_8x50_INFO(pm_info)->tvco; 3140 } 3141 if ((tvco < portmodVCOInvalid) || (tvco >= portmodVCOCount)) { 3142 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("TVCO configuration is invalid."))); 3143 } 3144 3145 if (tvco_pll_index == 1) { 3146 _SOC_IF_ERR_EXIT(_pm8x50_vco_to_pll_get(core_conf.interface.ref_clock, tvco, &pll1)); 3147 _SOC_IF_ERR_EXIT(_pm8x50_vco_to_pll_get(core_conf.interface.ref_clock, ovco, &pll0)); 3148 } else { 3149 _SOC_IF_ERR_EXIT(_pm8x50_vco_to_pll_get(core_conf.interface.ref_clock, tvco, &pll0)); 3150 _SOC_IF_ERR_EXIT(_pm8x50_vco_to_pll_get(core_conf.interface.ref_clock, ovco, &pll1)); 3151 } 3152 3153 core_conf.pll0_div_init_value = pll0; 3154 core_conf.pll1_div_init_value = pll1; 3155 3156 _SOC_IF_ERR_EXIT(phymod_core_status_t_init(&core_status)); 3157 core_status.pmd_active = 0; 3158 init_flags = PORTMOD_PORT_ADD_F_INIT_PASS1_GET(add_info) | PORTMOD_PORT_ADD_F_INIT_PASS2_GET(add_info); 3159 3160 if (PORTMOD_PORT_ADD_F_FIRMWARE_LOAD_VERIFY_GET(add_info)) { 3161 PHYMOD_CORE_INIT_F_FIRMWARE_LOAD_VERIFY_SET(&core_conf); 3162 } 3163 if (PORTMOD_PORT_ADD_F_INIT_PASS1_GET(add_info)) { 3164 PHYMOD_CORE_INIT_F_EXECUTE_PASS1_SET(&core_conf); 3165 } 3166 if (PORTMOD_PORT_ADD_F_INIT_PASS2_GET(add_info)) { 3167 PHYMOD_CORE_INIT_F_EXECUTE_PASS2_SET(&core_conf); 3168 } 3169 if (PORTMOD_PORT_ADD_F_INIT_PASS2_GET(add_info)) { 3170 PHYMOD_CORE_INIT_F_RESUME_AFTER_FW_LOAD_SET(&core_conf); 3171 } 3172 3173 if (PORTMOD_PORT_ADD_F_BYPASS_FW_CRC_CHECK_GET(add_info)) { 3174 PHYMOD_CORE_INIT_F_BYPASS_CRC_CHECK_SET(&core_conf); 3175 } 3176 3177 #ifdef FW_BCAST_DOWNLOAD 3178 if (PORTMOD_PORT_ADD_F_FIRMWARE_DOWNLOAD_BCAST_GET(add_info)) { 3179 PHYMOD_CORE_INIT_F_SERDES_FW_BCAST_SET(&core_conf); 3180 } 3181 #endif 3182 3183 3184 if (!PORTMOD_CORE_INIT_FLAG_INITIALZIED_GET(core_is_initialized)) { 3185 /* firmware load will happen after pass 1 */ 3186 if (!PORTMOD_CORE_INIT_FLAG_FIRMWARE_LOADED_GET(core_is_initialized) || 3187 PORTMOD_PORT_ADD_F_INIT_PASS2_GET(add_info)) { 3188 #if 0 3189 3190 if (PORTMOD_PORT_ADD_F_INIT_PASS1_GET(add_info) || init_flags == 0) { 3191 if (PM_8x50_INFO(pm_info)->rescal != -1) { 3192 sal_memcpy(&serdes_access, &(PM_8x50_INFO(pm_info)->int_core_access), sizeof(phymod_phy_access_t)); 3193 _SOC_IF_ERR_EXIT(phymod_phy_rescal_set(&serdes_access, 1, PM_8x50_INFO(pm_info)->rescal)); 3194 } 3195 } 3196 #endif 3197 _SOC_IF_ERR_EXIT(phymod_core_init(&PM_8x50_INFO(pm_info)->int_core_access, 3198 &core_conf, 3199 &core_status)); 3200 3201 if (PORTMOD_PORT_ADD_F_INIT_PASS1_GET(add_info) || init_flags == 0) { 3202 PORTMOD_CORE_INIT_FLAG_FIRMWARE_LOADED_SET(core_is_initialized); 3203 rv = SOC_WB_ENGINE_SET_VAR (unit, SOC_WB_ENGINE_PORTMOD, 3204 pm_info->wb_vars_ids[isCoreInitialized], 3205 &core_is_initialized); 3206 _SOC_IF_ERR_EXIT(rv); 3207 3208 rv = SOC_WB_ENGINE_SET_VAR (unit, SOC_WB_ENGINE_PORTMOD, 3209 pm_info->wb_vars_ids[originalTxLaneSwap], 3210 &tx_lane_map); 3211 _SOC_IF_ERR_EXIT(rv); 3212 3213 rv = SOC_WB_ENGINE_SET_VAR (unit, SOC_WB_ENGINE_PORTMOD, 3214 pm_info->wb_vars_ids[originalRxLaneSwap], 3215 &rx_lane_map); 3216 _SOC_IF_ERR_EXIT(rv); 3217 } 3218 if (PORTMOD_PORT_ADD_F_INIT_PASS2_GET(add_info) || init_flags == 0) { 3219 PORTMOD_CORE_INIT_FLAG_INITIALZIED_SET(core_is_initialized); 3220 rv = SOC_WB_ENGINE_SET_VAR (unit, SOC_WB_ENGINE_PORTMOD, 3221 pm_info->wb_vars_ids[isCoreInitialized], 3222 &core_is_initialized); 3223 _SOC_IF_ERR_EXIT(rv); 3224 } 3225 } 3226 } 3227 3228 exit: 3229 SOC_FUNC_RETURN; 3230 } 3231 3232 /*PM Core init routine*/ 3233 /* PM core init has 3 phase: 3234 * 1. Core probe: Probe serdes dispatch type. 3235 * 2. Pass1: Download FW, program ref_clk, polarity, lane map, etc. 3236 * 3. Pass2: PLL configuration, program UC core config, load PCS tables etc. 3237 */ 3238 int pm8x50_pm_serdes_core_init(int unit, 3239 int pm_id, 3240 pm_info_t pm_info, 3241 const portmod_port_add_info_t* add_info) 3242 { 3243 int init_all = 0; 3244 int rv = SOC_E_NONE; 3245 3246 SOC_INIT_FUNC_DEFS; 3247 3248 /* Update per core based database */ 3249 if (add_info->init_config.polarity_overwrite == 1) { 3250 sal_memcpy(&PM_8x50_INFO(pm_info)->polarity, 3251 &add_info->init_config.polarity[0], sizeof(phymod_polarity_t)); 3252 } 3253 if (add_info->init_config.lane_map_overwrite == 1) { 3254 sal_memcpy(&PM_8x50_INFO(pm_info)->lane_map, 3255 &add_info->init_config.lane_map[0], sizeof(phymod_lane_map_t)); 3256 } 3257 if (add_info->init_config.fw_load_method_overwrite == 1) { 3258 PM_8x50_INFO(pm_info)->fw_load_method = 3259 add_info->init_config.fw_load_method[0]; 3260 } 3261 if (add_info->init_config.ref_clk_overwrite == 1) { 3262 PM_8x50_INFO(pm_info)->ref_clk = add_info->init_config.ref_clk; 3263 } 3264 3265 init_all = (!PORTMOD_PORT_ADD_F_INIT_CORE_PROBE_GET(add_info) && 3266 !PORTMOD_PORT_ADD_F_INIT_PASS1_GET(add_info) && 3267 !PORTMOD_PORT_ADD_F_INIT_PASS2_GET(add_info)) ? 1 : 0; 3268 3269 /* probe serdes core */ 3270 if (PORTMOD_PORT_ADD_F_INIT_CORE_PROBE_GET(add_info) || init_all) { 3271 rv = _pm8x50_pm_core_probe(unit, pm_info, add_info); 3272 _SOC_IF_ERR_EXIT(rv); 3273 } 3274 3275 /* Return here if caller only request Core Probe */ 3276 if (!(PORTMOD_PORT_ADD_F_INIT_PASS1_GET(add_info)) && 3277 (PORTMOD_PORT_ADD_F_INIT_CORE_PROBE_GET(add_info))) { 3278 return (rv); 3279 } 3280 3281 /* core config for internal serdes. */ 3282 rv = _pm8x50_pm_serdes_core_init(unit, pm_info, add_info); 3283 _SOC_IF_ERR_EXIT(rv); 3284 3285 exit: 3286 SOC_FUNC_RETURN; 3287 } 3288 3289 STATIC 3290 int _pm8x50_pm_port_init(int unit, 3291 int port, 3292 pm_info_t pm_info, 3293 int internal_port, 3294 const portmod_port_add_info_t* add_info, 3295 int enable) 3296 { 3297 int rv, phy_acc; 3298 uint32 reg_val, flags; 3299 uint32 rsv_mask; 3300 SOC_INIT_FUNC_DEFS; 3301 3302 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 3303 if (internal_port == -1) { 3304 _SOC_EXIT_WITH_ERR(SOC_E_PORT, (_SOC_MSG("Invalid internal Port %d"), 3305 internal_port)); 3306 } 3307 3308 if (enable) { 3309 /* RSV Mask */ 3310 rsv_mask = 0; 3311 SHR_BITSET(&rsv_mask, 3); /* Receive terminate/code error */ 3312 SHR_BITSET(&rsv_mask, 4); /* CRC error */ 3313 SHR_BITSET(&rsv_mask, 6); /* Truncated/Frame out of Range */ 3314 SHR_BITSET(&rsv_mask, 17); /* RUNT detected*/ 3315 _SOC_IF_ERR_EXIT(pm8x50_port_mac_rsv_mask_set(unit, phy_acc, pm_info, rsv_mask)); 3316 3317 /* Init MAC */ 3318 flags = 0; 3319 if(PORTMOD_PORT_ADD_F_RX_SRIP_CRC_GET(add_info)) { 3320 flags |= CDMAC_INIT_F_RX_STRIP_CRC; 3321 3322 } 3323 3324 if(PORTMOD_PORT_ADD_F_TX_APPEND_CRC_GET(add_info)) { 3325 flags |= CDMAC_INIT_F_TX_APPEND_CRC; 3326 } 3327 3328 if(PORTMOD_PORT_ADD_F_TX_REPLACE_CRC_GET(add_info)) { 3329 flags |= CDMAC_INIT_F_TX_REPLACE_CRC; 3330 } 3331 3332 if(PORTMOD_PORT_ADD_F_TX_PASS_THROUGH_CRC_GET(add_info)) { 3333 flags |= CDMAC_INIT_F_TX_PASS_THROUGH_CRC_MODE; 3334 } 3335 3336 /* MIB counters are cleared in cdmac_init */ 3337 rv = cdmac_init(unit, phy_acc, flags); 3338 _SOC_IF_ERR_EXIT(rv); 3339 3340 /* LSS */ 3341 _SOC_IF_ERR_EXIT(READ_CDPORT_FAULT_LINK_STATUSr(unit, phy_acc, ®_val)); 3342 soc_reg_field_set(unit, CDPORT_FAULT_LINK_STATUSr, ®_val, REMOTE_FAULTf, 1); 3343 soc_reg_field_set(unit, CDPORT_FAULT_LINK_STATUSr, ®_val, LOCAL_FAULTf, 1); 3344 _SOC_IF_ERR_EXIT(WRITE_CDPORT_FAULT_LINK_STATUSr(unit, phy_acc, reg_val)); 3345 3346 /* Counter MAX size */ 3347 _SOC_IF_ERR_EXIT(pm8x50_port_cntmaxsize_set(unit, phy_acc, pm_info, 1518)); 3348 } 3349 3350 exit: 3351 SOC_FUNC_RETURN; 3352 } 3353 3354 /* 3355 * Perfom MAC soft reset, including drain cells procedure. 3356 * 3357 * Supported reset modes: IN, OUT, IN-OUT 3358 * 3359 * IN - set MAC in soft reset. 3360 * When reset_mode=IN the parameters saved_rx_enable, saved_mac_ctrl are outputs, 3361 * and should be sent back to this function when called with OUT. 3362 * OUT - get MAC out of soft reset. 3363 * When reset_mode=OUT the parameters saved_rx_enable, saved_mac_ctrl are inputs, 3364 * the values that should be passed in are the values returned from IN. 3365 * Example sequnece: 3366 * int saved_rx_enablel uint64 saved_mac_ctrl; 3367 * pm8x50_port_soft_reset(unit, port, pinfo, PM8X50_PORT_SOFT_RESET_MODE_IN, &saved_rx_enablel, &saved_mac_ctrl); 3368 * ... here the MAC is in reset ... 3369 * pm8x50_port_soft_reset(unit, port, pinfo, PM8X50_PORT_SOFT_RESET_MODE_OUT, &saved_rx_enablel, &saved_mac_ctrl); 3370 * IN-OUT - get MAC IN reset and then out of reset. 3371 * When reset_mode=INOUT, saved_rx_enable, saved_mac_ctrl can be set to NULL. 3372 */ 3373 STATIC 3374 int pm8x50_port_soft_reset(int unit, 3375 int port, 3376 pm_info_t pm_info, 3377 pm8x50_port_soft_reset_mode_t reset_mode, 3378 int *saved_rx_enable, 3379 uint64 *saved_mac_ctrl) 3380 { 3381 3382 int rv, rx_enable = 0; 3383 portmod_drain_cells_t drain_cells; 3384 uint32 cell_count; 3385 uint64 mac_ctrl; 3386 soc_timeout_t to; 3387 SOC_INIT_FUNC_DEFS; 3388 3389 /* Callback soft reset function */ 3390 if (PM_8x50_INFO(pm_info)->portmod_mac_soft_reset) { 3391 rv = PM_8x50_INFO(pm_info)->portmod_mac_soft_reset(unit, port, portmodCallBackActionTypePre); 3392 _SOC_IF_ERR_EXIT(rv); 3393 } 3394 3395 if (PM8X50_PORT_SOFT_RESET_MODE_OUT != reset_mode) { 3396 rv = cdmac_egress_queue_drain_get(unit, port, &mac_ctrl, &rx_enable); 3397 _SOC_IF_ERR_EXIT(rv); 3398 3399 /* return MAC state if required */ 3400 if ((NULL != saved_rx_enable) && (NULL != saved_mac_ctrl)) { 3401 *saved_rx_enable = rx_enable; 3402 COMPILER_64_COPY(*saved_mac_ctrl, mac_ctrl); 3403 } 3404 3405 /* Drain cells */ 3406 rv = cdmac_drain_cell_get(unit, port, &drain_cells); 3407 _SOC_IF_ERR_EXIT(rv); 3408 3409 /* Start TX FIFO draining */ 3410 rv = cdmac_drain_cell_start(unit, port); 3411 _SOC_IF_ERR_EXIT(rv); 3412 3413 /* De-assert SOFT_RESET to let the drain start */ 3414 rv = cdmac_soft_reset_set(unit, port, 0); 3415 _SOC_IF_ERR_EXIT(rv); 3416 3417 if (!SAL_BOOT_SIMULATION){ 3418 /* Wait until TX fifo cell count is 0 */ 3419 soc_timeout_init(&to, 250000, 0); 3420 for (;;) { 3421 rv = cdmac_txfifo_cell_cnt_get(unit, port, &cell_count); 3422 _SOC_IF_ERR_EXIT(rv); 3423 if (cell_count == 0) { 3424 break; 3425 } 3426 if (soc_timeout_check(&to)) { 3427 LOG_ERROR(BSL_LS_SOC_PORT,(BSL_META_UP(unit, port, 3428 "ERROR: u=%d p=%d timeout draining TX FIFO (%d cells remain)\n"), unit, port, cell_count)); 3429 return SOC_E_INTERNAL; 3430 } 3431 } 3432 } else { 3433 rv = cdmac_txfifo_cell_cnt_get(unit, port, &cell_count); 3434 _SOC_IF_ERR_EXIT(rv); 3435 } 3436 3437 /* Stop TX FIFO draining */ 3438 rv = cdmac_drain_cell_stop(unit, port, &drain_cells); 3439 _SOC_IF_ERR_EXIT(rv); 3440 3441 /* Put port into SOFT_RESET */ 3442 rv = cdmac_soft_reset_set(unit, port, 1); 3443 _SOC_IF_ERR_EXIT(rv); 3444 } 3445 3446 if(PM8X50_PORT_SOFT_RESET_MODE_IN != reset_mode) { 3447 if (PM_8x50_INFO(pm_info)->portmod_mac_soft_reset) { 3448 rv = PM_8x50_INFO(pm_info)->portmod_mac_soft_reset(unit, port, portmodCallBackActionTypeDuring); 3449 _SOC_IF_ERR_EXIT(rv); 3450 } 3451 3452 /* For out of reset only operation, use MAC state from input */ 3453 if (PM8X50_PORT_SOFT_RESET_MODE_OUT == reset_mode) { 3454 SOC_NULL_CHECK(saved_rx_enable); 3455 SOC_NULL_CHECK(saved_mac_ctrl); 3456 rx_enable = *saved_rx_enable; 3457 COMPILER_64_COPY(mac_ctrl, *saved_mac_ctrl); 3458 } 3459 3460 soc_reg64_field32_set(unit, CDMAC_CTRLr, &mac_ctrl, SOFT_RESETf, 0); /*make sure restored data wont put mac back in reset*/ 3461 3462 /* Enable TX, restore RX, de-assert SOFT_RESET */ 3463 rv = cdmac_egress_queue_drain_rx_en(unit, port, rx_enable); 3464 _SOC_IF_ERR_EXIT(rv); 3465 3466 /* Restore clmac_CTRL to original value */ 3467 rv = cdmac_mac_ctrl_set(unit, port, mac_ctrl); 3468 _SOC_IF_ERR_EXIT(rv); 3469 3470 /* Callback soft reset function */ 3471 if (PM_8x50_INFO(pm_info)->portmod_mac_soft_reset) { 3472 rv = PM_8x50_INFO(pm_info)->portmod_mac_soft_reset(unit, port, portmodCallBackActionTypePost); 3473 _SOC_IF_ERR_EXIT(rv); 3474 } 3475 } 3476 3477 exit: 3478 SOC_FUNC_RETURN; 3479 } 3480 3481 STATIC 3482 int _pm8x50_port_mac_drain_soft_reset(int unit, int port) 3483 { 3484 int rv; 3485 portmod_drain_cells_t drain_cells; 3486 uint32 cell_count; 3487 soc_timeout_t to; 3488 SOC_INIT_FUNC_DEFS; 3489 3490 /* Drain cells */ 3491 rv = cdmac_drain_cell_get(unit, port, &drain_cells); 3492 _SOC_IF_ERR_EXIT(rv); 3493 3494 /* Start TX FIFO draining */ 3495 rv = cdmac_drain_cell_start(unit, port); 3496 _SOC_IF_ERR_EXIT(rv); 3497 3498 /* De-assert SOFT_RESET to let the drain start */ 3499 rv = cdmac_soft_reset_set(unit, port, 0); 3500 _SOC_IF_ERR_EXIT(rv); 3501 3502 if (!SAL_BOOT_SIMULATION){ 3503 /* Wait until TX fifo cell count is 0 */ 3504 soc_timeout_init(&to, 250000, 0); 3505 for (;;) { 3506 rv = cdmac_txfifo_cell_cnt_get(unit, port, &cell_count); 3507 _SOC_IF_ERR_EXIT(rv); 3508 if (cell_count == 0) { 3509 break; 3510 } 3511 if (soc_timeout_check(&to)) { 3512 LOG_ERROR(BSL_LS_SOC_PORT,(BSL_META_UP(unit, port, 3513 "ERROR: u=%d p=%d timeout draining TX FIFO (%d cells remain)\n"), unit, port, cell_count)); 3514 return SOC_E_INTERNAL; 3515 } 3516 } 3517 } else { 3518 rv = cdmac_txfifo_cell_cnt_get(unit, port, &cell_count); 3519 _SOC_IF_ERR_EXIT(rv); 3520 } 3521 /* Stop TX FIFO draining */ 3522 rv = cdmac_drain_cell_stop(unit, port, &drain_cells); 3523 _SOC_IF_ERR_EXIT(rv); 3524 3525 /* Put port into SOFT_RESET */ 3526 rv = cdmac_soft_reset_set(unit, port, 1); 3527 _SOC_IF_ERR_EXIT(rv); 3528 3529 exit: 3530 SOC_FUNC_RETURN; 3531 } 3532 3533 STATIC 3534 int _pm8x50_port_rx_restore_mac_out_of_reset(int unit, int port, int rx_enable) 3535 { 3536 int rv; 3537 SOC_INIT_FUNC_DEFS; 3538 3539 /* Enable RX, de-assert SOFT_RESET */ 3540 rv = cdmac_egress_queue_drain_rx_en(unit, port, rx_enable); 3541 _SOC_IF_ERR_EXIT(rv); 3542 3543 exit: 3544 SOC_FUNC_RETURN; 3545 } 3546 3547 3548 /*Add new port*/ 3549 int pm8x50_port_attach(int unit, int port, pm_info_t pm_info, 3550 const portmod_port_add_info_t* add_info) 3551 { 3552 int port_index = -1, pm_is_active = 0, is_pcs_bypassed = 0; 3553 int rv = 0, port_i, my_i, found_first_active_lane; 3554 int phy, ii, nof_phys; 3555 portmod_pbmp_t port_phys_in_pm; 3556 phymod_phy_init_config_t init_config; 3557 portmod_access_get_params_t params; 3558 phymod_phy_access_t phy_access; 3559 phymod_phy_signalling_method_t signalling_mode; 3560 phymod_an_mode_type_t init_an_mode = phymod_AN_MODE_NONE; 3561 const portmod_speed_config_t *speed_config = &add_info->speed_config; 3562 int usr_cfg_idx, rlm_enabled = 0, rlm_state = PORTMOD_PORT_RLM_FSM_COUNT; 3563 uint32 timesync_enable_default = 0; 3564 SOC_INIT_FUNC_DEFS; 3565 3566 /* Get the first phy related to this port */ 3567 PORTMOD_PBMP_ASSIGN(port_phys_in_pm, add_info->phys); 3568 PORTMOD_PBMP_AND(port_phys_in_pm, PM_8x50_INFO(pm_info)->phys); 3569 3570 ii = 0; 3571 PORTMOD_PBMP_ITER(PM_8x50_INFO(pm_info)->phys, phy) { 3572 if(PORTMOD_PBMP_MEMBER(port_phys_in_pm, phy)) { 3573 rv = PM8x50_LANE2PORT_SET(unit, pm_info, ii, port); 3574 _SOC_IF_ERR_EXIT(rv); 3575 port_index = (port_index == -1 ? ii : port_index); 3576 } 3577 ii++; 3578 } 3579 3580 is_pcs_bypassed = PORTMOD_PORT_ADD_F_PCS_BYPASSED_GET(add_info) ? 1 : 0; 3581 rv = PM8x50_PORT_IS_PCS_BYPASSED_SET(unit, pm_info, is_pcs_bypassed, port_index); 3582 _SOC_IF_ERR_EXIT(rv); 3583 3584 /* initalize port */ 3585 rv = _pm8x50_pm_port_init(unit, port, pm_info, port_index, add_info, 1); 3586 _SOC_IF_ERR_EXIT(rv); 3587 3588 /* initialze phy */ 3589 _SOC_IF_ERR_EXIT(phymod_phy_init_config_t_init(&init_config)); 3590 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 3591 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 3592 ¶ms, 1, &phy_access, &nof_phys, NULL)); 3593 3594 3595 init_config.an_en = add_info->autoneg_en; 3596 init_config.cl72_en = add_info->link_training_en; 3597 init_config.op_mode = add_info->interface_config.port_op_mode; 3598 my_i = 0, usr_cfg_idx = 0; 3599 found_first_active_lane = 0; 3600 for(ii=0; ii<PM8X50_LANES_PER_CORE; ii++) { 3601 rv = PM8x50_LANE2PORT_GET(unit, pm_info, ii, &port_i); 3602 _SOC_IF_ERR_EXIT(rv); 3603 3604 if(port_i != port) { 3605 /* There is a difference between XGS and DNX devices. For DNX, a port can consist inconsecutive physical lanes. 3606 * For example, a port can consist lane 1 and 3 of the same core. For XGS, on the other hand, a port always consist 3607 * consecutive physical lanes. Therefore my_i below needs not be incremented for XGS devices. 3608 */ 3609 if(PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy_access.device_op_mode) && found_first_active_lane){ 3610 my_i++; 3611 } 3612 continue; 3613 } else{ 3614 found_first_active_lane = 1; 3615 } 3616 3617 _SOC_IF_ERR_EXIT(phymod_phy_media_type_tx_get(&phy_access, phymodMediaTypeChipToChip, &init_config.tx[my_i])); 3618 3619 if (PORTMOD_PORT_ADD_F_SKIP_SPEED_INIT_GET(add_info)) { 3620 /* If PORTMOD_PORT_ADD_F_SKIP_SPEED_INIT is set, set tx_taps to NRZ default */ 3621 signalling_mode = phymodSignallingMethodNRZ; 3622 } else { 3623 _pm8x50_signalling_method_get(is_pcs_bypassed, speed_config, &signalling_mode); 3624 } 3625 3626 if (PORTMOD_USER_SET_TX_PREEMPHASIS_BY_CONFIG_GET(add_info->init_config.tx_params_user_flag[usr_cfg_idx])) { 3627 init_config.tx[my_i].pre = add_info->init_config.tx_params[usr_cfg_idx].pre; 3628 init_config.tx[my_i].main = add_info->init_config.tx_params[usr_cfg_idx].main; 3629 init_config.tx[my_i].post = add_info->init_config.tx_params[usr_cfg_idx].post; 3630 init_config.tx[my_i].pre2 = add_info->init_config.tx_params[usr_cfg_idx].pre2; 3631 init_config.tx[my_i].post2 = add_info->init_config.tx_params[usr_cfg_idx].post2; 3632 init_config.tx[my_i].post3 = add_info->init_config.tx_params[usr_cfg_idx].post3; 3633 init_config.tx[my_i].tap_mode = add_info->init_config.tx_params[usr_cfg_idx].tap_mode; 3634 init_config.tx[my_i].sig_method = add_info->init_config.tx_params[usr_cfg_idx].sig_method; 3635 } else { 3636 /* Need to get the default values for tx taps */ 3637 _SOC_IF_ERR_EXIT(phymod_phy_tx_taps_default_get(&phy_access, signalling_mode, &init_config.tx[my_i])); 3638 } 3639 3640 usr_cfg_idx++; 3641 my_i++; 3642 } 3643 3644 _SOC_IF_ERR_EXIT(phymod_phy_init(&phy_access, &init_config)); 3645 3646 /* MAC SOFT_RESET will be released within pm8x50_port_speed_config_set */ 3647 if (!PORTMOD_PORT_ADD_F_SKIP_SPEED_INIT_GET(add_info)) { 3648 rv = pm8x50_port_speed_config_set(unit, port, pm_info, speed_config); 3649 } 3650 else if (!is_pcs_bypassed) 3651 { 3652 _SOC_IF_ERR_EXIT(pm8x50_port_soft_reset(unit, port, pm_info, PM8X50_PORT_SOFT_RESET_MODE_IN_OUT, NULL, NULL)); 3653 } 3654 3655 _SOC_IF_ERR_EXIT(rv); 3656 3657 /* Update WB DB */ 3658 rv = PM8x50_IS_ACTIVE_GET(unit, pm_info, &pm_is_active); 3659 _SOC_IF_ERR_EXIT(rv); 3660 if (!pm_is_active) { 3661 pm_is_active = 1; 3662 rv = PM8x50_IS_ACTIVE_SET(unit, pm_info, pm_is_active); 3663 _SOC_IF_ERR_EXIT(rv); 3664 } 3665 3666 rv = PM8x50_AN_MODE_SET(unit, pm_info, init_an_mode, port_index); 3667 _SOC_IF_ERR_EXIT(rv); 3668 3669 rv = PM8x50_MAX_SPEED_SET(unit, pm_info, add_info->interface_config.max_speed, port_index); 3670 _SOC_IF_ERR_EXIT(rv); 3671 3672 rv = PM8x50_TIMESYNC_ENABLE_SET(unit, pm_info, timesync_enable_default, port_index); 3673 _SOC_IF_ERR_EXIT(rv); 3674 3675 _SOC_IF_ERR_EXIT 3676 (PM8x50_RLM_ENABLE_SET(unit, pm_info, rlm_enabled, port_index)); 3677 3678 _SOC_IF_ERR_EXIT 3679 (PM8x50_RLM_STATE_SET(unit, pm_info, rlm_state, port_index)); 3680 3681 if (add_info->init_config.parity_enable) { 3682 _pm8x50_port_interrupt_all_enable_set(unit, port, 1); 3683 3684 } 3685 3686 exit: 3687 SOC_FUNC_RETURN; 3688 } 3689 3690 /*get port cores' phymod access*/ 3691 int pm8x50_pm_core_info_get(int unit, pm_info_t pm_info, int phyn, 3692 portmod_pm_core_info_t* core_info) 3693 { 3694 SOC_INIT_FUNC_DEFS; 3695 3696 if(phyn < 0) { 3697 phyn = PM8X50_MAX_NUM_PHYS; 3698 } 3699 3700 core_info->ref_clk = PM_8x50_INFO(pm_info)->ref_clk; 3701 sal_memcpy(&core_info->lane_map, &(PM_8x50_INFO(pm_info)->lane_map), 3702 sizeof(phymod_lane_map_t)); 3703 3704 SOC_FUNC_RETURN; 3705 } 3706 3707 /*Get PM phys.*/ 3708 int pm8x50_pm_phys_get(int unit, pm_info_t pm_info, portmod_pbmp_t* phys) 3709 { 3710 SOC_INIT_FUNC_DEFS; 3711 PORTMOD_PBMP_ASSIGN(*phys, PM_8x50_INFO(pm_info)->phys); 3712 SOC_FUNC_RETURN; 3713 } 3714 3715 /*Port remove in PM level*/ 3716 int pm8x50_port_detach(int unit, int port, pm_info_t pm_info) 3717 { 3718 int enable, invalid_port = -1, tmp_port, i = 0, flags = 0, pm_id; 3719 int is_last_one = TRUE, port_index = -1, fec_null = 0; 3720 const uint32 is_active = 0; 3721 int tvco_pll_index, ovco_pll_index; 3722 uint8_t ovco_pll_active_lane_bm, tvco_pll_active_lane_bm; 3723 uint8_t ovco_pll_adv_lane_bm, tvco_pll_adv_lane_bm, eth_active_lanes; 3724 portmod_access_get_params_t params; 3725 phymod_phy_access_t phy_access; 3726 int nof_phys; 3727 portmod_phy_timesync_config_t config; 3728 3729 SOC_INIT_FUNC_DEFS; 3730 3731 _SOC_IF_ERR_EXIT(portmod_port_periodic_callback_unregister(unit, port)); 3732 3733 tvco_pll_index = PM8X50_TVCO_PLL_INDEX_GET(pm_info); 3734 ovco_pll_index = (tvco_pll_index == 1)? 0: 1; 3735 3736 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 3737 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 3738 ¶ms, 1, &phy_access, &nof_phys, NULL)); 3739 _SOC_IF_ERR_EXIT(pm8x50_port_enable_get(unit, port, pm_info, flags, &enable)); 3740 if (enable) 3741 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("can't detach active port %d"), port)); 3742 3743 /* Disable 1588 */ 3744 config.flags = 0; 3745 _SOC_IF_ERR_EXIT(pm8x50_port_timesync_config_set(unit, port, pm_info, &config)); 3746 3747 /* Disable PCS for the port */ 3748 _SOC_IF_ERR_EXIT(phymod_phy_pcs_enable_set(&phy_access, 0)); 3749 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_active_lane_bm)); 3750 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_active_lane_bm)); 3751 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_adv_lane_bm)); 3752 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_adv_lane_bm)); 3753 3754 /* flexport workaround for 16nm flexportHW issue */ 3755 /* first get the port index */ 3756 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 3757 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info, i, &tmp_port)); 3758 if (tmp_port == port) { 3759 port_index = (port_index == -1 ? i : port_index); 3760 } 3761 } 3762 /* call port level port mode update */ 3763 _SOC_IF_ERR_EXIT(_pm8x50_pm_port_mode_update(unit, port, pm_info, port_index, 1)); 3764 /* call speed toggle workaround */ 3765 _SOC_IF_ERR_EXIT(phymod_phy_pcs_enable_set(&phy_access, FLEXPORT_SW_WAR_ENABLE)); 3766 /*-- Flexport workaround ends here. --*/ 3767 3768 3769 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 3770 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info, i, &tmp_port)); 3771 if (tmp_port == port) { 3772 port_index = (port_index == -1 ? i : port_index); 3773 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_SET(unit, pm_info, i, invalid_port)); 3774 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, fec_null)); 3775 ovco_pll_active_lane_bm &= ~(1 << i); 3776 tvco_pll_active_lane_bm &= ~(1 << i); 3777 ovco_pll_adv_lane_bm &= ~(1 << i); 3778 tvco_pll_adv_lane_bm &= ~(1 << i); 3779 } else if (tmp_port != invalid_port) { 3780 is_last_one = FALSE; 3781 } 3782 } 3783 3784 if (port_index == -1) 3785 _SOC_EXIT_WITH_ERR(SOC_E_PORT, (_SOC_MSG("Port %d wasn't found"), port)); 3786 3787 if ((!ovco_pll_active_lane_bm) && (!ovco_pll_adv_lane_bm)) { 3788 /* Power down OVCO if it's not in use */ 3789 _SOC_IF_ERR_EXIT(phymod_phy_pll_pwrdn(&phy_access, ovco_pll_index, 1)); 3790 PM_8x50_INFO(pm_info)->ovco = portmodVCOInvalid; 3791 } 3792 3793 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, ovco_pll_active_lane_bm)); 3794 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, tvco_pll_active_lane_bm)); 3795 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, ovco_pll_adv_lane_bm)); 3796 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, tvco_pll_adv_lane_bm)); 3797 3798 _SOC_IF_ERR_EXIT(_pm8x50_pm_active_eth_lanes_get(unit, pm_info, ð_active_lanes)); 3799 3800 if (!eth_active_lanes && !tvco_pll_active_lane_bm) { 3801 /* 3802 * Power down TVCO if 3803 * 1. No active ethernet ports, and 3804 * 2. No ILKN port is using TVCO. 3805 * Note: Since no active eth port -> there are no adv ports -> no need to check tvco_pll_adv_lane_bm 3806 */ 3807 _SOC_IF_ERR_EXIT(phymod_phy_pll_pwrdn(&phy_access, tvco_pll_index, 1)); 3808 PM_8x50_INFO(pm_info)->tvco = portmodVCOInvalid; 3809 } 3810 3811 /*deinit PM in case of last one*/ 3812 if (is_last_one) { 3813 _SOC_IF_ERR_EXIT(portmod_port_pm_id_get(unit, port, &pm_id)); 3814 _SOC_IF_ERR_EXIT(pm8x50_pm_enable(unit, pm_id, pm_info, 0)); 3815 _SOC_IF_ERR_EXIT(PM8x50_IS_ACTIVE_SET(unit, pm_info, is_active)); 3816 _SOC_IF_ERR_EXIT(PM8x50_IS_CORE_INITIALIZED_SET(unit, pm_info, is_active)); 3817 3818 PM_8x50_INFO(pm_info)->int_core_access.type = phymodDispatchTypeInvalid; 3819 } 3820 3821 exit: 3822 SOC_FUNC_RETURN; 3823 } 3824 3825 /*Port replace in PM level*/ 3826 int pm8x50_port_replace(int unit, int port, pm_info_t pm_info, int new_port) 3827 { 3828 int i, tmp_port; 3829 int rv = 0; 3830 SOC_INIT_FUNC_DEFS; 3831 3832 /* replace old port with new port */ 3833 for(i = 0; i < MAX_PORTS_PER_PM8X50; i++) { 3834 rv = PM8x50_LANE2PORT_GET(unit, pm_info, i, &tmp_port); 3835 _SOC_IF_ERR_EXIT(rv); 3836 if (tmp_port == port) { 3837 rv = PM8x50_LANE2PORT_SET(unit, pm_info, i, new_port); 3838 _SOC_IF_ERR_EXIT(rv); 3839 } 3840 } 3841 3842 exit: 3843 SOC_FUNC_RETURN; 3844 } 3845 3846 3847 /*Port enable*/ 3848 int pm8x50_port_enable_set(int unit, int port, pm_info_t pm_info, 3849 int flags, int enable) 3850 { 3851 int actual_flags = flags; 3852 int cdmac_flags = 0, port_index; 3853 uint32 is_bypassed = 0, bitmap[1]; 3854 phymod_phy_access_t phy_access; 3855 portmod_access_get_params_t params; 3856 int nof_phys = 0; 3857 SOC_INIT_FUNC_DEFS; 3858 3859 /* If no RX\TX flags - set both*/ 3860 if((!PORTMOD_PORT_ENABLE_TX_GET(flags)) && 3861 (!PORTMOD_PORT_ENABLE_RX_GET(flags))) { 3862 PORTMOD_PORT_ENABLE_RX_SET(actual_flags); 3863 PORTMOD_PORT_ENABLE_TX_SET(actual_flags); 3864 } 3865 3866 /* if no MAC\Phy flags - set both*/ 3867 if((!PORTMOD_PORT_ENABLE_PHY_GET(flags)) && 3868 (!PORTMOD_PORT_ENABLE_MAC_GET(flags))) { 3869 PORTMOD_PORT_ENABLE_PHY_SET(actual_flags); 3870 PORTMOD_PORT_ENABLE_MAC_SET(actual_flags); 3871 } 3872 3873 /* 3874 * if MAC is set and having only either RX or TX set 3875 * is invalid combination 3876 */ 3877 if((PORTMOD_PORT_ENABLE_MAC_GET(actual_flags)) && 3878 (!PORTMOD_PORT_ENABLE_PHY_GET(actual_flags))) { 3879 3880 if((!PORTMOD_PORT_ENABLE_TX_GET(actual_flags)) || 3881 (!PORTMOD_PORT_ENABLE_RX_GET(actual_flags))) { 3882 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 3883 (_SOC_MSG("MAC RX and TX can't be enabled separately"))); 3884 } 3885 } 3886 3887 if(PORTMOD_PORT_ENABLE_PHY_GET(actual_flags)) { 3888 /* Only internal phy supported. */ 3889 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 3890 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, 3891 pm_info, ¶ms, 1, &phy_access, 3892 &nof_phys, NULL)); 3893 } 3894 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, bitmap)); 3895 _SOC_IF_ERR_EXIT(PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &is_bypassed, port_index)); 3896 3897 if(enable){ 3898 if((PORTMOD_PORT_ENABLE_MAC_GET(actual_flags)) && (!is_bypassed)) { 3899 3900 if(!PM_8x50_INFO(pm_info)->portmod_mac_soft_reset) 3901 { 3902 _SOC_IF_ERR_EXIT(cdmac_enable_set(unit, port, cdmac_flags, 1)); 3903 } 3904 else 3905 { 3906 /* Enable CDMAC RX,TX, skip SOFT_RESET */ 3907 _SOC_IF_ERR_EXIT(cdmac_tx_enable_set (unit, port, 1)); 3908 _SOC_IF_ERR_EXIT(cdmac_rx_enable_set (unit, port, 1)); 3909 _SOC_IF_ERR_EXIT(pm8x50_port_soft_reset(unit, port, pm_info, PM8X50_PORT_SOFT_RESET_MODE_IN_OUT, NULL, NULL)); 3910 } 3911 } 3912 3913 if(PORTMOD_PORT_ENABLE_PHY_GET(actual_flags)) { 3914 if (PORTMOD_PORT_ENABLE_TX_GET(actual_flags)) { 3915 _SOC_IF_ERR_EXIT( 3916 phymod_phy_tx_lane_control_set(&phy_access, 3917 phymodTxSquelchOff)); 3918 } 3919 if (PORTMOD_PORT_ENABLE_RX_GET(actual_flags)) { 3920 _SOC_IF_ERR_EXIT( 3921 phymod_phy_rx_lane_control_set(&phy_access, 3922 phymodRxSquelchOff)); 3923 } 3924 } /* PORTMOD_PORT_ENABLE_PHY_GET */ 3925 } else {/* disable */ 3926 if (PORTMOD_PORT_ENABLE_PHY_GET(actual_flags)) { 3927 3928 if (PORTMOD_PORT_ENABLE_TX_GET(actual_flags)) { 3929 _SOC_IF_ERR_EXIT( 3930 phymod_phy_tx_lane_control_set(&phy_access, 3931 phymodTxSquelchOn)); 3932 } 3933 3934 if (PORTMOD_PORT_ENABLE_RX_GET(actual_flags)) { 3935 _SOC_IF_ERR_EXIT( 3936 phymod_phy_rx_lane_control_set(&phy_access, 3937 phymodRxSquelchOn)); 3938 } 3939 } 3940 3941 if((PORTMOD_PORT_ENABLE_MAC_GET(actual_flags)) && (!is_bypassed)) { 3942 _SOC_IF_ERR_EXIT(cdmac_enable_set(unit, port, cdmac_flags, 0)); 3943 } 3944 } 3945 3946 exit: 3947 SOC_FUNC_RETURN; 3948 } 3949 3950 int pm8x50_port_enable_get(int unit, int port, pm_info_t pm_info, 3951 int flags, int* enable) 3952 { 3953 int nof_phys = 0, port_index; 3954 int phy_enable = 1, mac_enable = 1; 3955 int mac_rx_enable = 0, mac_tx_enable = 0; 3956 uint32 is_bypassed = 0, bitmap[1]; 3957 int actual_flags = flags; 3958 phymod_phy_access_t phy_access; 3959 portmod_access_get_params_t params; 3960 phymod_phy_tx_lane_control_t tx_control = phymodTxSquelchOn; 3961 phymod_phy_rx_lane_control_t rx_control = phymodRxSquelchOn; 3962 SOC_INIT_FUNC_DEFS; 3963 SOC_NULL_CHECK(pm_info); 3964 3965 /* If no RX\TX flags - set both*/ 3966 if((!PORTMOD_PORT_ENABLE_TX_GET(flags)) && 3967 (!PORTMOD_PORT_ENABLE_RX_GET(flags))) { 3968 PORTMOD_PORT_ENABLE_RX_SET(actual_flags); 3969 PORTMOD_PORT_ENABLE_TX_SET(actual_flags); 3970 } 3971 3972 /* if no MAC\Phy flags - set both*/ 3973 if((!PORTMOD_PORT_ENABLE_PHY_GET(flags)) && 3974 (!PORTMOD_PORT_ENABLE_MAC_GET(flags))) { 3975 PORTMOD_PORT_ENABLE_PHY_SET(actual_flags); 3976 PORTMOD_PORT_ENABLE_MAC_SET(actual_flags); 3977 } 3978 3979 if(PORTMOD_PORT_ENABLE_PHY_GET(actual_flags)) { 3980 /* Only internal phy supported. */ 3981 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 3982 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, 3983 pm_info, ¶ms, 1, &phy_access, 3984 &nof_phys, NULL)); 3985 } 3986 3987 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, bitmap)); 3988 _SOC_IF_ERR_EXIT(PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &is_bypassed, port_index)); 3989 3990 if (PORTMOD_PORT_ENABLE_PHY_GET(actual_flags)) { 3991 _SOC_IF_ERR_EXIT(phymod_phy_tx_lane_control_get(&phy_access, 3992 &tx_control)); 3993 _SOC_IF_ERR_EXIT(phymod_phy_rx_lane_control_get(&phy_access, 3994 &rx_control)); 3995 3996 /* TBD - set phy_enable to 1 for SIM */ 3997 phy_enable = 0; 3998 3999 if (PORTMOD_PORT_ENABLE_RX_GET(actual_flags)) { 4000 phy_enable |= (rx_control == phymodRxSquelchOn) ? 0 : 1; 4001 } 4002 if (PORTMOD_PORT_ENABLE_TX_GET(actual_flags)) { 4003 phy_enable |= (tx_control == phymodTxSquelchOn) ? 0 : 1; 4004 } 4005 } 4006 4007 if ((PORTMOD_PORT_ENABLE_MAC_GET(actual_flags)) && (!is_bypassed)) { 4008 mac_enable = 0; 4009 4010 if (PORTMOD_PORT_ENABLE_RX_GET(actual_flags)) { 4011 _SOC_IF_ERR_EXIT(cdmac_enable_get(unit, port, 4012 CDMAC_ENABLE_SET_FLAGS_RX_EN, 4013 &mac_rx_enable)); 4014 mac_enable |= (mac_rx_enable)? 1: 0; 4015 } 4016 4017 if (PORTMOD_PORT_ENABLE_TX_GET(actual_flags)) { 4018 _SOC_IF_ERR_EXIT(cdmac_enable_get(unit, port, 4019 CDMAC_ENABLE_SET_FLAGS_TX_EN, 4020 &mac_tx_enable)); 4021 mac_enable |= (mac_tx_enable)? 1: 0; 4022 } 4023 } 4024 4025 *enable = (mac_enable && phy_enable); 4026 4027 exit: 4028 SOC_FUNC_RETURN; 4029 } 4030 4031 /* 4032 * Function: 4033 * _pm8x50_vcos_request_allocate_internal. 4034 * 4035 * Purpose: 4036 * Function gets current TVCO, OVCO and tries to accommodate input VCO requests. 4037 * 4038 * Inputs: 4039 * unit: unit number 4040 * flags: Special flags for vco allocation. (PM8X50_TVCO_SUPPORT_20P625G) 4041 * required_vcos_bmp: required VCO bitmap 4042 * current_tvco: current TVCO value 4043 * current_ovco: current OVCO value 4044 * Output: 4045 * current_tvco: if validation pass, current_tvco will indicate new value TVCO value 4046 * current_ovco: if validation pass, current_ovco will indicate new value OVCO value 4047 */ 4048 STATIC 4049 int _pm8x50_vcos_request_allocate_internal( 4050 int unit, 4051 uint32 flags, 4052 const pm8x50_vcos_bmp_t required_vcos_bmp, 4053 portmod_vco_type_t *current_tvco, 4054 portmod_vco_type_t *current_ovco) 4055 { 4056 pm8x50_vcos_bmp_t required_vcos_bmp_temp; 4057 int is_tvco_in_use, is_ovco_in_use, is_eth_drv_tvco; 4058 portmod_vco_type_t required_vco; 4059 int required_pcs_bypass; 4060 4061 SOC_INIT_FUNC_DEFS; 4062 4063 is_tvco_in_use = (*current_tvco == portmodVCOInvalid) ? 0 : 1; 4064 is_ovco_in_use = (*current_ovco == portmodVCOInvalid) ? 0 : 1; 4065 4066 required_vcos_bmp_temp = required_vcos_bmp; 4067 4068 while (!PM8x50_VCO_BMP_EMPTY(required_vcos_bmp_temp)) { 4069 is_eth_drv_tvco = _pm8x50_ethernet_tvco_check(unit, flags, *current_tvco); 4070 /* 4071 * 1. Get next required VCO. 4072 * 2. Clear VCO from temp bitmap 4073 */ 4074 _SOC_IF_ERR_EXIT( 4075 _pm8x50_required_vco_value_iter(unit, &required_vcos_bmp_temp, &required_vco, &required_pcs_bypass)); 4076 4077 /* Try to match with TVCO current configuration */ 4078 if (is_tvco_in_use) { 4079 if (required_vco == *current_tvco) { 4080 /* 4081 * If tvco match AND eth port is requried AND request is not TVCO supported => there is no match. 4082 * For pcs bypass no restrictions. 4083 */ 4084 if (required_pcs_bypass || (!required_pcs_bypass && is_eth_drv_tvco)) { 4085 continue; 4086 } 4087 } 4088 } 4089 4090 /* Try to match with OVCO current configuration */ 4091 if (is_ovco_in_use) { 4092 if (required_vco == *current_ovco) { 4093 /* 4094 * If ovco match AND eth port is requried AND tvco is not eth => there is no match. 4095 * For pcs bypass no restrictions. 4096 */ 4097 if (required_pcs_bypass || (!required_pcs_bypass && is_eth_drv_tvco)) { 4098 continue; 4099 } 4100 } 4101 } 4102 4103 /* For TVCO ethernet rates, try first to lock TVCO. For non-TVCO ethernet rate - try to first lock OVCO*/ 4104 if (_pm8x50_ethernet_tvco_check(unit, flags, required_vco)) { 4105 if (!is_tvco_in_use) { 4106 *current_tvco = required_vco; 4107 is_tvco_in_use = 1; 4108 continue; 4109 } else if (!is_ovco_in_use) { 4110 /* 4111 * Can use OVCO for ILKN ports with no condition, 4112 * Can use OVCO for ETH only if TVCO is ETH 4113 */ 4114 if (required_pcs_bypass || (!required_pcs_bypass && is_eth_drv_tvco)) { 4115 *current_ovco = required_vco; 4116 is_ovco_in_use = 1; 4117 continue; 4118 } 4119 } 4120 } else { 4121 /* non-TVCO ethernet rate */ 4122 if (!is_ovco_in_use) { 4123 if ((required_pcs_bypass) || (!required_pcs_bypass && is_eth_drv_tvco)) { 4124 *current_ovco = required_vco; 4125 is_ovco_in_use = 1; 4126 continue; 4127 } 4128 } else if (!is_tvco_in_use) { 4129 if (required_pcs_bypass) { 4130 /* 4131 * Support setting TVCO if bypass 4132 */ 4133 *current_tvco = required_vco; 4134 is_tvco_in_use = 1; 4135 continue; 4136 } 4137 } 4138 } 4139 4140 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4141 (_SOC_MSG("Can not accommodate VCO settings.\n request [VCO %d, PCS bypass %d], state [TVCO %d, OVCO %d]\n"), required_vco, required_pcs_bypass, *current_tvco, *current_ovco)); 4142 4143 } 4144 4145 exit: 4146 SOC_FUNC_RETURN; 4147 } 4148 4149 4150 /* 4151 * Function: 4152 * pm8x50_vcos_request_allocate. 4153 * 4154 * Purpose: 4155 * Function gets current TVCO, OVCO and tries to accommodate input VCO requests. 4156 * Function splits required VCO bitmap into 2 bitmaps - 4157 * - VCO rates existing in current state 4158 * - new VCO rates. 4159 * Function first tries serve new VCO rates and then existing VCO rates. 4160 * 4161 * Inputs: 4162 * unit: unit number 4163 * flags: special flag for allocation. (PM8X50_TVCO_SUPPORT_20P625G) 4164 * required_vcos_bmp: required VCO bitmap 4165 * current_tvco: current TVCO value 4166 * current_ovco: current OVCO value 4167 * Output: 4168 * current_tvco: If validation pass, current_tvco will indicate new value TVCO value 4169 * current_ovco: If validation pass, current_ovco will indicate new value OVCO value 4170 */ 4171 4172 int pm8x50_vcos_request_allocate( 4173 int unit, 4174 uint32 flags, 4175 const pm8x50_vcos_bmp_t required_vcos_bmp, 4176 portmod_vco_type_t *current_tvco, 4177 portmod_vco_type_t *current_ovco) 4178 { 4179 pm8x50_vcos_bmp_t vco_bmp, required_new_vcos_bmp = 0, required_existing_vcos_bmp = 0; 4180 pm8x50_vcos_bmp_t required_vcos_bmp_temp; 4181 portmod_vco_type_t required_vco; 4182 int required_pcs_bypass; 4183 4184 SOC_INIT_FUNC_DEFS; 4185 4186 /* Copy request bitmap */ 4187 required_vcos_bmp_temp = required_vcos_bmp; 4188 4189 /* Handle special case of 20.625G Ethernet only request --> Add 25.871 VCO to request to drive TVCO*/ 4190 if (!PM8X50_TVCO_SUPPORT_20P625G_GET(flags) && 4191 PM8x50_VCO_BMP_20P625G_ETH_ONLY(required_vcos_bmp) && 4192 (*current_tvco == portmodVCOInvalid) && ((*current_ovco == portmodVCOInvalid) || (*current_ovco == portmodVCO20P625G))) 4193 { 4194 PM8x50_VCO_ETH_25P781G_SET(required_vcos_bmp_temp); 4195 } 4196 4197 /* Handle special case of 25G Ethernet only request --> Add 25.871 VCO request to drive TVCO */ 4198 if (PM8x50_VCO_BMP_25G_ETH_ONLY(required_vcos_bmp) && 4199 (*current_tvco == portmodVCOInvalid) && 4200 ((*current_ovco == portmodVCOInvalid) || (*current_ovco == portmodVCO25G))) { 4201 PM8x50_VCO_ETH_25P781G_SET(required_vcos_bmp_temp); 4202 } 4203 4204 /* 4205 * Split required VCOs bitmap into new/existing requests bitmaps 4206 */ 4207 4208 while (!PM8x50_VCO_BMP_EMPTY(required_vcos_bmp_temp)) 4209 { 4210 /* 4211 * 1. Get next required VCO. 4212 * 2. Clear VCO from temp bitmap 4213 */ 4214 _SOC_IF_ERR_EXIT( 4215 _pm8x50_required_vco_value_iter(unit, &required_vcos_bmp_temp, &required_vco, &required_pcs_bypass)); 4216 4217 /* Get VCO bitmap */ 4218 _SOC_IF_ERR_EXIT(_pm8x50_required_vco_bitmap_get(unit, required_vco, required_pcs_bypass, &vco_bmp)); 4219 4220 if (required_vco == *current_tvco || required_vco == *current_ovco) 4221 { 4222 /* Add to existing VCO bitmap */ 4223 required_existing_vcos_bmp |= vco_bmp; 4224 } 4225 else 4226 { 4227 /* Add to new VCO bitmap */ 4228 required_new_vcos_bmp |= vco_bmp; 4229 } 4230 } 4231 4232 /* Serve new VCOs */ 4233 _SOC_IF_ERR_EXIT( 4234 _pm8x50_vcos_request_allocate_internal(unit, flags, required_new_vcos_bmp, current_tvco, current_ovco)); 4235 4236 /* Serve existing VCOs */ 4237 _SOC_IF_ERR_EXIT( 4238 _pm8x50_vcos_request_allocate_internal(unit, flags, required_existing_vcos_bmp, current_tvco, current_ovco)); 4239 4240 exit: 4241 SOC_FUNC_RETURN; 4242 } 4243 4244 STATIC 4245 int _pm8x50_fec_lanebitmap_get(int unit, 4246 pm_info_t pm_info, 4247 uint8 *rs528_bitmap, 4248 uint8 *rs544_bitmap, 4249 uint8 *rs272_bitmap) 4250 { 4251 int i, rv; 4252 portmod_fec_t tmp_fec; 4253 4254 SOC_INIT_FUNC_DEFS; 4255 4256 *rs528_bitmap = 0; 4257 *rs544_bitmap = 0; 4258 *rs272_bitmap = 0; 4259 /* Get RS528, RS544, RS272 usage bitmap from WB */ 4260 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++){ 4261 rv = PM8x50_LANE2FEC_GET(unit, pm_info, i, &tmp_fec); 4262 _SOC_IF_ERR_EXIT(rv); 4263 if (tmp_fec == PORTMOD_PORT_PHY_FEC_RS_FEC) { 4264 *rs528_bitmap |= 1 << i; 4265 } else if ((tmp_fec == PORTMOD_PORT_PHY_FEC_RS_544) || 4266 (tmp_fec == PORTMOD_PORT_PHY_FEC_RS_544_2XN)) { 4267 *rs544_bitmap |= 1 << i; 4268 } else if ((tmp_fec == PORTMOD_PORT_PHY_FEC_RS_272) || 4269 (tmp_fec == PORTMOD_PORT_PHY_FEC_RS_272_2XN)) { 4270 *rs272_bitmap |= 1 << i; 4271 } 4272 } 4273 exit: 4274 SOC_FUNC_RETURN; 4275 } 4276 4277 /* 4278 * Function: 4279 *_pm8x50_vcos_setting_validate 4280 * 4281 * Purpose: 4282 * VCOs setting validation. 4283 * 4284 * Inputs: 4285 * unit: unit number; 4286 * pm_info: pm_info data structure; 4287 * ports: Logical port bitmaps which reqiring the input vcos; 4288 * required_vcos_bmp: Required vcos bitmap; 4289 * flag: PLL switch flag; 4290 * Output: 4291 * vco_setting: If validation pass, vco_setting will indicating 4292 * what's the new vco rates and whether they are new or not; 4293 * vco_setting.num_speeds and vco_setting.speed_config_list 4294 * are no care in this function. 4295 */ 4296 int _pm8x50_vcos_setting_validate(int unit, 4297 pm_info_t pm_info, 4298 const portmod_pbmp_t* ports, 4299 pm8x50_vcos_bmp_t required_vcos_bmp, 4300 int flag, 4301 portmod_pm_vco_setting_t* vco_setting) 4302 { 4303 uint8_t ovco_pll_active_lane_bitmap, tvco_pll_active_lane_bitmap, ovco_pll_adv_lane_bitmap, tvco_pll_adv_lane_bitmap; 4304 int is_tvco_in_use, is_ovco_in_use; 4305 portmod_vco_type_t current_tvco, current_ovco; 4306 uint32_t port_lane_mask = 0, lane_bitmap[1]; 4307 int port, port_index; 4308 uint8_t active_eth_lanes; 4309 uint32 flags = 0; 4310 4311 SOC_INIT_FUNC_DEFS; 4312 4313 _SOC_IF_ERR_EXIT( 4314 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_active_lane_bitmap)); 4315 _SOC_IF_ERR_EXIT( 4316 PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_active_lane_bitmap)); 4317 _SOC_IF_ERR_EXIT( 4318 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_adv_lane_bitmap)); 4319 _SOC_IF_ERR_EXIT( 4320 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_adv_lane_bitmap)); 4321 _SOC_IF_ERR_EXIT( 4322 _pm8x50_pm_active_eth_lanes_get(unit, pm_info, &active_eth_lanes)); 4323 4324 /* 4325 * Get lane mask for the input ports 4326 */ 4327 PORTMOD_PBMP_ITER(*ports, port) { 4328 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, lane_bitmap)); 4329 port_lane_mask |= lane_bitmap[0]; 4330 } 4331 4332 /* Remove input lanes from ovco and check if it is in use */ 4333 ovco_pll_active_lane_bitmap &= ~port_lane_mask; 4334 ovco_pll_adv_lane_bitmap &= ~port_lane_mask; 4335 is_ovco_in_use = ((ovco_pll_active_lane_bitmap | ovco_pll_adv_lane_bitmap) == 0) ? 0 : 1; 4336 if (is_ovco_in_use) 4337 { 4338 /* ovco in use (not refering to the ports that are currently requested) */ 4339 current_ovco = PM_8x50_INFO(pm_info)->ovco; 4340 } 4341 else 4342 { 4343 /* 4344 * ovco not in use (not refering to the ports that are currently requested) 4345 * currently set as invalid (ovco might be allcoate by VCO algorithm) 4346 */ 4347 current_ovco = portmodVCOInvalid; 4348 } 4349 4350 /* Remove input lanes from tvco and check if it is in use */ 4351 tvco_pll_active_lane_bitmap &= ~port_lane_mask; 4352 tvco_pll_adv_lane_bitmap &= ~port_lane_mask; 4353 active_eth_lanes &= ~port_lane_mask; 4354 is_tvco_in_use = ((tvco_pll_active_lane_bitmap | tvco_pll_adv_lane_bitmap | active_eth_lanes) == 0) ? 0 : 1; 4355 if (is_tvco_in_use) 4356 { 4357 /* tvco in use (not refering to the ports that are currently requested) */ 4358 current_tvco = PM_8x50_INFO(pm_info)->tvco; 4359 } 4360 else 4361 { 4362 /* 4363 * tvco not in use (not refering to the ports that are currently requested) 4364 * currently set as invalid (tvco might be allcoate by VCO algorithm) 4365 */ 4366 current_tvco = portmodVCOInvalid; 4367 } 4368 4369 if (PM_8x50_INFO(pm_info)->allow_20p625g_tvco) { 4370 PM8X50_TVCO_SUPPORT_20P625G_SET(flags); 4371 } 4372 /* Try to allocate required VCOs */ 4373 _SOC_IF_ERR_EXIT( 4374 pm8x50_vcos_request_allocate(unit, flags, required_vcos_bmp, ¤t_tvco, ¤t_ovco)); 4375 4376 /* Set output */ 4377 vco_setting->tvco = current_tvco; 4378 vco_setting->is_tvco_new = (PM_8x50_INFO(pm_info)->tvco == current_tvco) ? 0 : 1; 4379 vco_setting->ovco = current_ovco; 4380 vco_setting->is_ovco_new = (PM_8x50_INFO(pm_info)->ovco == current_ovco) ? 0 : 1; 4381 4382 exit: 4383 SOC_FUNC_RETURN; 4384 } 4385 4386 /* 4387 * Validate if a set of speed can be configured for given PORTMACRO without 4388 * affecting the other active ports. 4389 * 4390 * Inputs: 4391 * unit: unit number; 4392 * pm_id portmacro ID; 4393 * pm_info: pm_info data structure; 4394 * ports: Logical port bitmaps which reqiring the input vcos; 4395 * flag: PLL switch flag. 4396 * 4397 * Output: 4398 * vco_setting: If validation pass, vco_setting will indicating 4399 * what's the new vco rates and whether they are new or not; 4400 */ 4401 int pm8x50_pm_speed_config_validate(int unit, 4402 int pm_id, 4403 pm_info_t pm_info, 4404 const portmod_pbmp_t* ports, 4405 int flag, 4406 portmod_pm_vco_setting_t* vco_setting) 4407 { 4408 int i, rv, pam4_eth_req = 0; 4409 portmod_vco_type_t vco; 4410 pm8x50_vcos_bmp_t required_vcos_bmp = 0, required_vco_bmp_temp = 0; 4411 int is_pcs_bypass; 4412 uint8_t rs528_bm = 0, rs544_bm = 0, rs272_bm = 0, affected_bm = 0; 4413 int nof_phys, port; 4414 phymod_phy_access_t phy_access; 4415 portmod_access_get_params_t params; 4416 pm_version_t version; 4417 uint32 fec_validate_flags = 0; 4418 phymod_phy_signalling_method_t signalling_method; 4419 SOC_INIT_FUNC_DEFS; 4420 4421 /* Get RS FEC usage bitmaps from WB */ 4422 _SOC_IF_ERR_EXIT(_pm8x50_fec_lanebitmap_get(unit, pm_info, &rs528_bm, &rs544_bm, &rs272_bm)); 4423 4424 _SOC_IF_ERR_EXIT(_pm8x50_pm_version_get(unit, pm_info, &version)); 4425 if (version.tech_process == PM_TECH_16NM) { 4426 PM8X50_PM_VERSION_F_REV0_16NM_SET(fec_validate_flags); 4427 } 4428 /* Remove the input ports from FEC usage bitmaps*/ 4429 PORTMOD_PBMP_ITER(*ports, port) { 4430 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 4431 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 4432 ¶ms, 1, &phy_access, &nof_phys, NULL)); 4433 rs528_bm &= ~phy_access.access.lane_mask; 4434 rs544_bm &= ~phy_access.access.lane_mask; 4435 rs272_bm &= ~phy_access.access.lane_mask; 4436 } 4437 4438 /* Get the VCOs required by the input speed config list */ 4439 for (i = 0; i < vco_setting->num_speeds; i++) { 4440 vco = portmodVCOInvalid; 4441 rv = _pm8x50_port_speed_config_to_vco_get(&(vco_setting->speed_config_list[i]), 4442 vco_setting->speed_for_pcs_bypass_port[i], &vco); 4443 if (rv == SOC_E_CONFIG) { 4444 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 4445 (_SOC_MSG("Can not support speed: %d num_lane: %d fec: %d"), 4446 vco_setting->speed_config_list[i].speed, 4447 vco_setting->speed_config_list[i].num_lane, 4448 vco_setting->speed_config_list[i].fec)); 4449 } 4450 4451 is_pcs_bypass = vco_setting->speed_for_pcs_bypass_port[i]; 4452 _SOC_IF_ERR_EXIT(_pm8x50_required_vco_bitmap_get(unit, vco, is_pcs_bypass, &required_vco_bmp_temp)); 4453 required_vcos_bmp |= required_vco_bmp_temp; 4454 4455 _pm8x50_signalling_method_get(vco_setting->speed_for_pcs_bypass_port[i], 4456 &(vco_setting->speed_config_list[i]), 4457 &signalling_method); 4458 if ((signalling_method == phymodSignallingMethodPAM4) && 4459 !vco_setting->speed_for_pcs_bypass_port[i]) { 4460 pam4_eth_req = 1; 4461 } 4462 4463 if ((vco_setting->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_272) || 4464 (vco_setting->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_272_2XN)) { 4465 _SOC_IF_ERR_EXIT(_pm8x50_lanebitmap_set(vco_setting->port_starting_lane_list[i], 4466 vco_setting->speed_config_list[i].num_lane, 4467 &rs272_bm)); 4468 } else if ((vco_setting->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_544) || 4469 (vco_setting->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_544_2XN)) { 4470 _SOC_IF_ERR_EXIT(_pm8x50_lanebitmap_set(vco_setting->port_starting_lane_list[i], 4471 vco_setting->speed_config_list[i].num_lane, 4472 &rs544_bm)); 4473 } else if (vco_setting->speed_config_list[i].fec == PORTMOD_PORT_PHY_FEC_RS_FEC) { 4474 _SOC_IF_ERR_EXIT(_pm8x50_lanebitmap_set(vco_setting->port_starting_lane_list[i], 4475 vco_setting->speed_config_list[i].num_lane, 4476 &rs528_bm)); 4477 } 4478 4479 } 4480 4481 /* Validate FEC settings for RS528, RS544 and RS272 */ 4482 _SOC_IF_ERR_EXIT(_pm8x50_fec_validate(unit, fec_validate_flags, rs528_bm, rs544_bm, rs272_bm, &affected_bm)); 4483 4484 _SOC_IF_ERR_EXIT(_pm8x50_vcos_setting_validate(unit, pm_info, ports, required_vcos_bmp, flag, vco_setting)); 4485 4486 if (pam4_eth_req && (vco_setting->tvco == portmodVCO20P625G)) { 4487 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4488 (_SOC_MSG("Can not accommodate VCO settings.\n Current TVCO does not support Ethernet PAM4 speeds.\n"))); 4489 } 4490 exit: 4491 SOC_FUNC_RETURN; 4492 } 4493 4494 /*Port speed validation.*/ 4495 int pm8x50_port_speed_config_validate(int unit, 4496 int port, 4497 pm_info_t pm_info, 4498 const portmod_speed_config_t* speed_config, 4499 portmod_pbmp_t* affected_pbmp) 4500 { 4501 int rv, i, tmp_port, port_num_lanes, port_index, port_is_pcs_bypassed; 4502 portmod_vco_type_t required_vco; 4503 uint8_t ovco_pll_active_lane_bitmap, tvco_pll_active_lane_bitmap, ovco_pll_adv_lane_bitmap, tvco_pll_adv_lane_bitmap; 4504 uint32_t port_lane_mask[1]; 4505 uint8_t affected_lane_bitmap = 0, pm_is_full_bypassed, active_eth_lanes; 4506 uint8_t rs528_bm = 0, rs544_bm = 0, rs272_bm = 0; 4507 pm_version_t version; 4508 uint32 flags = 0; 4509 phymod_phy_signalling_method_t signalling_method; 4510 SOC_INIT_FUNC_DEFS; 4511 4512 /* clear the affected_pbmp first */ 4513 PORTMOD_PBMP_CLEAR(*affected_pbmp); 4514 4515 /* Get lane_mask and number of lanes for the port from DB */ 4516 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, port_lane_mask)); 4517 _SOC_IF_ERR_EXIT(PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &port_is_pcs_bypassed, port_index)); 4518 4519 /* Check speed_config->lane_num against lane number stored in DB */ 4520 if (!port_is_pcs_bypassed) 4521 { 4522 PORTMOD_BIT_COUNT(port_lane_mask[0], port_num_lanes); 4523 if (port_num_lanes != speed_config->num_lane) { 4524 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4525 (_SOC_MSG("Invalid lane number request on exising logical port."))); 4526 } 4527 } 4528 4529 /* Get RS528, RS544, RS272 usage bitmap from WB */ 4530 _SOC_IF_ERR_EXIT(_pm8x50_fec_lanebitmap_get(unit, pm_info, &rs528_bm, &rs544_bm, &rs272_bm)); 4531 4532 rs528_bm &= ~port_lane_mask[0]; 4533 rs544_bm &= ~port_lane_mask[0]; 4534 rs272_bm &= ~port_lane_mask[0]; 4535 if (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_FEC) { 4536 rs528_bm |= port_lane_mask[0]; 4537 } else if ((speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_544) || 4538 (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_544_2XN)) { 4539 rs544_bm |= port_lane_mask[0]; 4540 } else if ((speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_272) || 4541 (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_272_2XN)) { 4542 rs272_bm |= port_lane_mask[0]; 4543 } 4544 4545 _SOC_IF_ERR_EXIT(_pm8x50_pm_version_get(unit, pm_info, &version)); 4546 if (version.tech_process == PM_TECH_16NM) { 4547 PM8X50_PM_VERSION_F_REV0_16NM_SET(flags); 4548 } 4549 4550 /* Validate FEC settings for RS528, RS544 and RS272 */ 4551 rv = _pm8x50_fec_validate(unit, flags, rs528_bm, rs544_bm, rs272_bm, &affected_lane_bitmap); 4552 if (rv != SOC_E_NONE) { 4553 /* If FEC validate fails, return affected port bit map */ 4554 affected_lane_bitmap &= ~port_lane_mask[0]; 4555 for(i = 0 ; i < MAX_PORTS_PER_PM8X50; i++){ 4556 if ((affected_lane_bitmap >> i) & 1) { 4557 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info, i, &tmp_port)); 4558 PORTMOD_PBMP_PORT_ADD(*affected_pbmp, tmp_port); 4559 } 4560 } 4561 return rv; 4562 } 4563 4564 _SOC_IF_ERR_EXIT( 4565 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_active_lane_bitmap)); 4566 _SOC_IF_ERR_EXIT( 4567 PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_active_lane_bitmap)); 4568 _SOC_IF_ERR_EXIT( 4569 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_adv_lane_bitmap)); 4570 _SOC_IF_ERR_EXIT( 4571 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_adv_lane_bitmap)); 4572 _SOC_IF_ERR_EXIT( 4573 _pm8x50_pm_active_eth_lanes_get(unit, pm_info, &active_eth_lanes)); 4574 4575 /* Remove port lane mask from ovco_pll_active_lane_bitmap, ovco_pll_adv_lane_bitmap */ 4576 ovco_pll_active_lane_bitmap &= ~port_lane_mask[0]; 4577 ovco_pll_adv_lane_bitmap &= ~port_lane_mask[0]; 4578 4579 /* Remove port lane mask from tvco_pll_active_lane_bitmap, tvco_pll_adv_lane_bitmap */ 4580 tvco_pll_active_lane_bitmap &= ~port_lane_mask[0]; 4581 tvco_pll_adv_lane_bitmap &= ~port_lane_mask[0]; 4582 4583 pm_is_full_bypassed = ((active_eth_lanes & ~port_lane_mask[0]) == 0) ? 1 : 0; 4584 4585 /* Verify and get the required VCO */ 4586 rv = _pm8x50_port_speed_config_to_vco_get(speed_config, port_is_pcs_bypassed, &required_vco); 4587 if (rv == SOC_E_CONFIG) { 4588 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 4589 (_SOC_MSG("Speed config is not supported"))); 4590 } 4591 4592 _pm8x50_signalling_method_get(port_is_pcs_bypassed, speed_config, &signalling_method); 4593 if (!port_is_pcs_bypassed && 4594 (signalling_method == phymodSignallingMethodPAM4) && 4595 (PM_8x50_INFO(pm_info)->tvco == portmodVCO20P625G) && 4596 (tvco_pll_adv_lane_bitmap || tvco_pll_active_lane_bitmap || 4597 ovco_pll_adv_lane_bitmap || ovco_pll_active_lane_bitmap)) { 4598 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4599 (_SOC_MSG("Can not support Ethernet PAM4 speeds when TVCO is 20.625G."))); 4600 } else if (PORTMOD_VCO_PCS_BYPASS_DEDICATED(PM_8x50_INFO(pm_info)->tvco) && !port_is_pcs_bypassed) { 4601 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4602 (_SOC_MSG("Can not accommodate VCO settings. TVCO is dedicated for PCS bypassed ports! \n"))); 4603 } else if (required_vco == PM_8x50_INFO(pm_info)->tvco 4604 || required_vco == PM_8x50_INFO(pm_info)->ovco 4605 || (ovco_pll_active_lane_bitmap == 0 && ovco_pll_adv_lane_bitmap == 0) 4606 || (pm_is_full_bypassed && tvco_pll_active_lane_bitmap == 0 && tvco_pll_adv_lane_bitmap == 0)) { 4607 /* 4608 * 1. no vco change required 4609 * 2. OR, ovco is free to change 4610 * 3. OR, tvco is free to change if previous PM bypass mode is full bypass 4611 */ 4612 return SOC_E_NONE; 4613 } else if (ovco_pll_active_lane_bitmap & ovco_pll_adv_lane_bitmap) { 4614 /* OVCO is used by resolved AN port */ 4615 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4616 (_SOC_MSG("Can not accommodate VCO settings due to resolved AN port(s)."))); 4617 } else if (ovco_pll_active_lane_bitmap || ovco_pll_adv_lane_bitmap) { 4618 /* OVCO is used by FS port or is advertiesd by AN port */ 4619 /* affected_lane_bitmap in this case should include ports that are actively using ovco or advertising the ovco */ 4620 affected_lane_bitmap = ovco_pll_active_lane_bitmap | ovco_pll_adv_lane_bitmap; 4621 for( i = 0 ; i < MAX_PORTS_PER_PM8X50; i++){ 4622 if ((affected_lane_bitmap >> i) & 1) { 4623 rv = PM8x50_LANE2PORT_GET(unit, pm_info, i, &tmp_port); 4624 _SOC_IF_ERR_EXIT(rv); 4625 PORTMOD_PBMP_PORT_ADD(*affected_pbmp, tmp_port); 4626 } 4627 } 4628 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4629 (_SOC_MSG("Can not accommodate VCO settings."))); 4630 } else { 4631 /* coverity[dead_error_line] */ 4632 return SOC_E_PARAM; 4633 } 4634 4635 exit: 4636 SOC_FUNC_RETURN; 4637 } 4638 4639 /* 4640 * This API reconfig the VCO rates of the PM. 4641 * 4642 * 'pm8x50_pm_speed_config_validate' need to be called before this function. 4643 * Only when pm8x50_pm_speed_config_validate reuturns E_NONE and indicates 4644 * VCO change requirement, user can call this API to change VCOs. 4645 * 4646 * Two VCO values are always 4647 * required by this API regardless of whether the caller intends to change 4648 * one or two VCO rates. 4649 * vco[0]: TVCO. 4650 * vco[1]: OVCO. 4651 */ 4652 int pm8x50_pm_vco_reconfig(int unit, 4653 int pm_id, 4654 pm_info_t pm_info, 4655 const portmod_vco_type_t* vco) 4656 { 4657 uint8_t active_eth_lanes, new_ovco_active_lanes; 4658 uint8_t ovco_pll_active_lane_bm, tvco_pll_active_lane_bm; 4659 uint8_t ovco_pll_adv_lane_bm, tvco_pll_adv_lane_bm, zero = 0; 4660 portmod_vco_type_t cur_tvco = PM_8x50_INFO(pm_info)->tvco; 4661 portmod_vco_type_t cur_ovco = PM_8x50_INFO(pm_info)->ovco; 4662 uint32_t pll_div; 4663 int tvco_pll_index, ovco_pll_index; 4664 phymod_phy_access_t phy_access; 4665 int fec_null = 0, i; 4666 uint8_t ovco_active_lanes_bitmap, ovco_adv_lanes_bitmap, ovco_lanes_bitmap; 4667 SOC_INIT_FUNC_DEFS; 4668 4669 tvco_pll_index = PM8X50_TVCO_PLL_INDEX_GET(pm_info); 4670 ovco_pll_index = (tvco_pll_index == 1)? 0: 1; 4671 4672 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_active_lane_bm)); 4673 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_active_lane_bm)); 4674 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_adv_lane_bm)); 4675 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_adv_lane_bm)); 4676 _SOC_IF_ERR_EXIT(_pm8x50_pm_active_eth_lanes_get(unit, pm_info, &active_eth_lanes)); 4677 4678 if (cur_tvco != vco[0]) { 4679 /* TVCO need to be changed */ 4680 PM_8x50_INFO(pm_info)->tvco = vco[0]; 4681 /* Get PLL_DIV */ 4682 _SOC_IF_ERR_EXIT(_pm8x50_vco_to_pll_get(PM_8x50_INFO(pm_info)->ref_clk, vco[0], &pll_div)); 4683 4684 sal_memcpy (&phy_access, &(PM_8x50_INFO(pm_info)->int_core_access), 4685 sizeof(phymod_phy_access_t)); 4686 4687 if (pll_div != phymod_TSCBH_PLL_DIVNONE) { 4688 if (active_eth_lanes == (tvco_pll_adv_lane_bm | tvco_pll_active_lane_bm | 4689 ovco_pll_adv_lane_bm | ovco_pll_active_lane_bm)) { 4690 /* 4691 * Set lane_mask to 0xFF for the following two cases: 4692 * 4693 * 1. If active_eth_lanes != 0, meaning there are only ethernet ports 4694 * in the PM, it is safe to set lane_mask to 0xFF. 4695 * 2. If active_eth_lanes == 0, meaning there is no active ports in 4696 * the PM, it is safe to set lane_mask to 0xFF. 4697 */ 4698 phy_access.access.lane_mask = 0xFF; 4699 } else { 4700 /* 4701 * There are ILKN ports in the PM, lane_mask should include: 4702 * 4703 * 1. All ethernet lanes 4704 * 2. ILKN lanes using TVCO. 4705 */ 4706 phy_access.access.lane_mask = active_eth_lanes | tvco_pll_active_lane_bm; 4707 } 4708 _SOC_IF_ERR_EXIT( 4709 phymod_phy_pll_reconfig(&phy_access, tvco_pll_index, pll_div)); 4710 } else { 4711 /* will pwoer down this PLL */ 4712 _SOC_IF_ERR_EXIT(phymod_phy_pll_pwrdn(&phy_access, tvco_pll_index, 1)); 4713 } 4714 4715 /* For Ethernet mode, TVCO change will reset the whole serdes core. 4716 * So we will clear: 4717 * 1. the lane bitmaps for both PLLs. 4718 * 2. FEC type for all lanes. 4719 */ 4720 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, zero)); 4721 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, zero)); 4722 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, zero)); 4723 _SOC_IF_ERR_EXIT(PM8x50_TVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, zero)); 4724 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 4725 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, fec_null)); 4726 } 4727 /* 4728 * Since TVCO has been changed, need to remove the Ethernet lanes in 4729 * ovco_pll_active_lane_bm. 4730 */ 4731 new_ovco_active_lanes = ovco_pll_active_lane_bm & ~active_eth_lanes; 4732 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, new_ovco_active_lanes)); 4733 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, zero)); 4734 } 4735 4736 if (cur_ovco != vco[1]) { 4737 /* OVCO need to be changed */ 4738 PM_8x50_INFO(pm_info)->ovco = vco[1]; 4739 /* next get the OVCO's PLL divider */ 4740 _SOC_IF_ERR_EXIT(_pm8x50_vco_to_pll_get(PM_8x50_INFO(pm_info)->ref_clk, vco[1], &pll_div)); 4741 4742 sal_memcpy (&phy_access, &(PM_8x50_INFO(pm_info)->int_core_access), 4743 sizeof(phymod_phy_access_t)); 4744 /*once ilkn support is added, the phy_access lane mask needs to be adjusted */ 4745 if (pll_div !=phymod_TSCBH_PLL_DIVNONE) { 4746 _SOC_IF_ERR_EXIT( 4747 phymod_phy_pll_reconfig(&phy_access, ovco_pll_index, pll_div)); 4748 } else { 4749 _SOC_IF_ERR_EXIT(phymod_phy_pll_pwrdn(&phy_access, ovco_pll_index, 1)); 4750 } 4751 4752 /* Clear FEC usage for all the OVCO lanes */ 4753 _SOC_IF_ERR_EXIT( 4754 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_active_lanes_bitmap)); 4755 _SOC_IF_ERR_EXIT( 4756 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_adv_lanes_bitmap)); 4757 ovco_lanes_bitmap = ovco_active_lanes_bitmap | ovco_adv_lanes_bitmap; 4758 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 4759 if ((ovco_lanes_bitmap >> i) & 0x1) { 4760 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, fec_null)); 4761 } 4762 } 4763 4764 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, zero)); 4765 _SOC_IF_ERR_EXIT(PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, zero)); 4766 } 4767 4768 exit: 4769 SOC_FUNC_RETURN; 4770 } 4771 4772 /* set/get the speed config for the specified port.*/ 4773 int pm8x50_port_speed_config_set(int unit, int port, pm_info_t pm_info, const portmod_speed_config_t* speed_config) 4774 { 4775 portmod_access_get_params_t params; 4776 phymod_phy_access_t phy_access; 4777 uint64 mac_ctrl; 4778 phymod_phy_signalling_method_t signalling_mode; 4779 int nof_phys, i, rx_enable = 0, port_is_pcs_bypassed; 4780 portmod_pbmp_t affected_pbmp; 4781 portmod_pmd_lane_config_t portmod_lane_config; 4782 phymod_phy_speed_config_t phy_speed_config; 4783 phymod_phy_pll_state_t old_pll_state, new_pll_state; 4784 uint32 lane_config, port_lane_mask; 4785 uint8 tvco_pll_lanes_bitmap, ovco_pll_lanes_bitmap; 4786 portmod_vco_type_t required_vco; 4787 phymod_an_mode_type_t an_mode = phymod_AN_MODE_NONE; 4788 int port_index; 4789 uint32 is_bypassed = 0; 4790 uint32 bitmap[1]; 4791 4792 SOC_INIT_FUNC_DEFS; 4793 4794 COMPILER_64_ZERO(mac_ctrl); 4795 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_t_init(&phy_speed_config)); 4796 4797 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, bitmap)); 4798 _SOC_IF_ERR_EXIT(PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &is_bypassed, port_index)); 4799 4800 if(!PM_8x50_INFO(pm_info)->portmod_mac_soft_reset) 4801 { 4802 /* Get original MAC CTRL */ 4803 _SOC_IF_ERR_EXIT(cdmac_egress_queue_drain_get(unit, port, &mac_ctrl, &rx_enable)); 4804 4805 4806 /* Disable MAC RX, drain MAC FIFO, assert MAC SOFT_RESET */ 4807 _SOC_IF_ERR_EXIT(_pm8x50_port_mac_drain_soft_reset(unit, port)); 4808 } 4809 else if (!is_bypassed) 4810 { 4811 _SOC_IF_ERR_EXIT(pm8x50_port_soft_reset(unit, port, pm_info, PM8X50_PORT_SOFT_RESET_MODE_IN, &rx_enable, &mac_ctrl)); 4812 } 4813 4814 /* Validate speed_config */ 4815 _SOC_IF_ERR_EXIT(pm8x50_port_speed_config_validate(unit, port, pm_info, speed_config, &affected_pbmp)); 4816 4817 /* Update port_mode */ 4818 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &port_lane_mask)); 4819 _SOC_IF_ERR_EXIT(_pm8x50_pm_port_mode_update(unit, port, pm_info, port_index, speed_config->num_lane)); 4820 4821 _SOC_IF_ERR_EXIT( 4822 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_lanes_bitmap)); 4823 _SOC_IF_ERR_EXIT( 4824 PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_lanes_bitmap)); 4825 4826 4827 old_pll_state.pll0_lanes_bitmap = ovco_pll_lanes_bitmap; 4828 old_pll_state.pll1_lanes_bitmap = tvco_pll_lanes_bitmap; 4829 4830 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 4831 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 4832 ¶ms, 1, &phy_access, &nof_phys, NULL)); 4833 4834 port_is_pcs_bypassed = PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_GET(phy_access.device_op_mode); 4835 _SOC_IF_ERR_EXIT(_pm8x50_port_speed_config_to_vco_get(speed_config, port_is_pcs_bypassed, &required_vco)); 4836 4837 port_lane_mask = phy_access.access.lane_mask; 4838 4839 if (required_vco == PM_8x50_INFO(pm_info)->tvco) { 4840 tvco_pll_lanes_bitmap |= port_lane_mask; 4841 ovco_pll_lanes_bitmap &= ~port_lane_mask; 4842 } else if (required_vco == PM_8x50_INFO(pm_info)->ovco) { 4843 ovco_pll_lanes_bitmap |= port_lane_mask; 4844 tvco_pll_lanes_bitmap &= ~port_lane_mask; 4845 } else { 4846 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 4847 (_SOC_MSG("VCO need to be reconfigured before changing speed."))); 4848 } 4849 /* Decode the lane_config in speed_config */ 4850 lane_config = speed_config->lane_config; 4851 /* Retrieve the default lane config */ 4852 _pm8x50_signalling_method_get(is_bypassed, speed_config, &signalling_mode); 4853 if (lane_config == -1) { 4854 _SOC_IF_ERR_EXIT( 4855 phymod_phy_lane_config_default_get(&phy_access, signalling_mode, &portmod_lane_config.pmd_firmware_lane_config)); 4856 portmod_lane_config.pam4_channel_loss = 0; 4857 } else { 4858 if (signalling_mode == phymodSignallingMethodPAM4) { 4859 PORTMOD_PORT_PHY_LANE_CONFIG_FORCE_PAM4_SET(lane_config); 4860 PORTMOD_PORT_PHY_LANE_CONFIG_FORCE_NRZ_CLEAR(lane_config); 4861 } else { 4862 PORTMOD_PORT_PHY_LANE_CONFIG_FORCE_NRZ_SET(lane_config); 4863 PORTMOD_PORT_PHY_LANE_CONFIG_FORCE_PAM4_CLEAR(lane_config); 4864 PORTMOD_PORT_PHY_LANE_CONFIG_FORCE_ES_CLEAR(lane_config); 4865 PORTMOD_PORT_PHY_LANE_CONFIG_FORCE_NS_CLEAR(lane_config); 4866 } 4867 _SOC_IF_ERR_EXIT( 4868 portmod_common_pmd_lane_config_decode(lane_config, &portmod_lane_config)); 4869 } 4870 4871 if (!is_bypassed) { 4872 if (speed_config->fec == PORTMOD_PORT_PHY_FEC_NONE) { 4873 phy_speed_config.fec_type = phymod_fec_None; 4874 } else if (speed_config->fec == PORTMOD_PORT_PHY_FEC_BASE_R) { 4875 phy_speed_config.fec_type = phymod_fec_CL74; 4876 } else if (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_FEC) { 4877 phy_speed_config.fec_type = phymod_fec_CL91; 4878 } else if (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_544) { 4879 phy_speed_config.fec_type = phymod_fec_RS544; 4880 } else if (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_272) { 4881 phy_speed_config.fec_type = phymod_fec_RS272; 4882 } else if (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_544_2XN) { 4883 phy_speed_config.fec_type = phymod_fec_RS544_2XN; 4884 } else if (speed_config->fec == PORTMOD_PORT_PHY_FEC_RS_272_2XN) { 4885 phy_speed_config.fec_type = phymod_fec_RS272_2XN; 4886 } 4887 } 4888 4889 phy_speed_config.data_rate = speed_config->speed; 4890 phy_speed_config.linkTraining = speed_config->link_training; 4891 phy_speed_config.PAM4_channel_loss = portmod_lane_config.pam4_channel_loss; 4892 phy_speed_config.pmd_lane_config = portmod_lane_config.pmd_firmware_lane_config; 4893 4894 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_set(&phy_access, &phy_speed_config, &old_pll_state, &new_pll_state)); 4895 4896 if(!PM_8x50_INFO(pm_info)->portmod_mac_soft_reset) 4897 { 4898 /* Enable MAC RX, De-assert MAC SOFT_RESET */ 4899 _SOC_IF_ERR_EXIT(_pm8x50_port_rx_restore_mac_out_of_reset(unit, port, rx_enable)); 4900 /* Restore original MAC CONTROL */ 4901 _SOC_IF_ERR_EXIT(cdmac_mac_ctrl_set(unit, port, mac_ctrl)); 4902 } 4903 else if (!is_bypassed) 4904 { 4905 _SOC_IF_ERR_EXIT(pm8x50_port_soft_reset(unit, port, pm_info, PM8X50_PORT_SOFT_RESET_MODE_OUT, &rx_enable, &mac_ctrl)); 4906 } 4907 4908 /* Update PLL active lane bitmaps */ 4909 _SOC_IF_ERR_EXIT( 4910 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, ovco_pll_lanes_bitmap)); 4911 _SOC_IF_ERR_EXIT( 4912 PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, tvco_pll_lanes_bitmap)); 4913 4914 /* Clear the adv lane bitmap for the port because it's configured as a force speed port */ 4915 _SOC_IF_ERR_EXIT( 4916 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &ovco_pll_lanes_bitmap)); 4917 _SOC_IF_ERR_EXIT( 4918 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &tvco_pll_lanes_bitmap)); 4919 ovco_pll_lanes_bitmap &= ~port_lane_mask; 4920 tvco_pll_lanes_bitmap &= ~port_lane_mask; 4921 _SOC_IF_ERR_EXIT( 4922 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, ovco_pll_lanes_bitmap)); 4923 _SOC_IF_ERR_EXIT( 4924 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, tvco_pll_lanes_bitmap)); 4925 4926 /* Clear an_mode for the port to force user set new abilities before enable AN later on */ 4927 _SOC_IF_ERR_EXIT(PM8x50_AN_MODE_SET(unit, pm_info, an_mode, port_index)); 4928 4929 if (!is_bypassed) { 4930 /* Update FEC usage in WB */ 4931 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 4932 if ((port_lane_mask >> i) & 0x1) { 4933 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, speed_config->fec)); 4934 } 4935 } 4936 } 4937 4938 /* update FEC type for RLM usage */ 4939 _SOC_IF_ERR_EXIT(PM8x50_ORIGINAL_FEC_SET(unit, pm_info, phy_speed_config.fec_type, port_index)); 4940 4941 exit: 4942 SOC_FUNC_RETURN; 4943 } 4944 4945 int pm8x50_port_speed_config_get(int unit, int port, pm_info_t pm_info, portmod_speed_config_t* speed_config) 4946 { 4947 portmod_access_get_params_t params; 4948 phymod_phy_access_t phy_access; 4949 int nof_phys, port_num_lanes; 4950 uint32_t lane_config; 4951 portmod_pmd_lane_config_t portmod_lane_config; 4952 phymod_phy_speed_config_t phy_speed_config; 4953 phymod_autoneg_status_t an_status; 4954 4955 SOC_INIT_FUNC_DEFS; 4956 4957 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 4958 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 4959 ¶ms, 1, &phy_access, &nof_phys, NULL)); 4960 PORTMOD_BIT_COUNT(phy_access.access.lane_mask, port_num_lanes); 4961 4962 _SOC_IF_ERR_EXIT(pm8x50_port_autoneg_status_get(unit, port, pm_info, &an_status)); 4963 4964 if (an_status.enabled && an_status.locked) { 4965 speed_config->num_lane = an_status.resolved_num_lane; 4966 } else { 4967 speed_config->num_lane = port_num_lanes; 4968 } 4969 4970 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_t_init(&phy_speed_config)); 4971 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_get(&phy_access, &phy_speed_config)); 4972 4973 /* for the RLM speed mode, need to update the num_lane */ 4974 if ((phy_speed_config.data_rate == 150000) || 4975 (phy_speed_config.data_rate == 350000) || 4976 (phy_speed_config.data_rate == 300000)) { 4977 speed_config->num_lane = phy_speed_config.data_rate / 50000; 4978 } 4979 4980 portmod_lane_config.pam4_channel_loss = phy_speed_config.PAM4_channel_loss; 4981 portmod_lane_config.pmd_firmware_lane_config = phy_speed_config.pmd_lane_config; 4982 /* Encode the lane_config in speed_config */ 4983 _SOC_IF_ERR_EXIT( 4984 portmod_common_pmd_lane_config_encode(&portmod_lane_config, &lane_config)); 4985 4986 if (phy_speed_config.fec_type == phymod_fec_None) { 4987 speed_config->fec = PORTMOD_PORT_PHY_FEC_NONE; 4988 } else if (phy_speed_config.fec_type == phymod_fec_CL74) { 4989 speed_config->fec = PORTMOD_PORT_PHY_FEC_BASE_R; 4990 } else if (phy_speed_config.fec_type == phymod_fec_CL91) { 4991 speed_config->fec = PORTMOD_PORT_PHY_FEC_RS_FEC; 4992 } else if (phy_speed_config.fec_type == phymod_fec_RS544) { 4993 speed_config->fec = PORTMOD_PORT_PHY_FEC_RS_544; 4994 } else if (phy_speed_config.fec_type == phymod_fec_RS272) { 4995 speed_config->fec = PORTMOD_PORT_PHY_FEC_RS_272; 4996 } else if (phy_speed_config.fec_type == phymod_fec_RS544_2XN) { 4997 speed_config->fec = PORTMOD_PORT_PHY_FEC_RS_544_2XN; 4998 } else if (phy_speed_config.fec_type == phymod_fec_RS272_2XN) { 4999 speed_config->fec = PORTMOD_PORT_PHY_FEC_RS_272_2XN; 5000 } 5001 5002 speed_config->speed = phy_speed_config.data_rate; 5003 speed_config->link_training = phy_speed_config.linkTraining; 5004 speed_config->lane_config = lane_config; 5005 5006 exit: 5007 SOC_FUNC_RETURN; 5008 } 5009 5010 /*Port cl72 set\get*/ 5011 int pm8x50_port_cl72_set(int unit, int port, pm_info_t pm_info, uint32 enable) 5012 { 5013 int nof_phys; 5014 portmod_access_get_params_t params; 5015 phymod_phy_access_t phy_access; 5016 SOC_INIT_FUNC_DEFS; 5017 5018 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5019 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5020 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5021 if (!SAL_BOOT_SIMULATION) { 5022 _SOC_IF_ERR_EXIT 5023 (phymod_phy_cl72_set(&phy_access, enable)); 5024 } 5025 5026 exit: 5027 SOC_FUNC_RETURN; 5028 } 5029 5030 int pm8x50_port_cl72_get(int unit, int port, pm_info_t pm_info, uint32* enable) 5031 { 5032 int nof_phys; 5033 portmod_access_get_params_t params; 5034 phymod_phy_access_t phy_access; 5035 SOC_INIT_FUNC_DEFS; 5036 5037 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5038 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5039 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5040 5041 if (!SAL_BOOT_SIMULATION) { 5042 _SOC_IF_ERR_EXIT 5043 (phymod_phy_cl72_get(&phy_access, enable)); 5044 } 5045 5046 exit: 5047 SOC_FUNC_RETURN; 5048 } 5049 5050 /*Get port cl72 status*/ 5051 int pm8x50_port_cl72_status_get(int unit, int port, pm_info_t pm_info, 5052 phymod_cl72_status_t* status) 5053 { 5054 int nof_phys; 5055 portmod_access_get_params_t params; 5056 phymod_phy_access_t phy_access; 5057 SOC_INIT_FUNC_DEFS; 5058 5059 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5060 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5061 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5062 5063 if (!SAL_BOOT_SIMULATION) { 5064 _SOC_IF_ERR_EXIT 5065 (phymod_phy_cl72_status_get(&phy_access, status)); 5066 } 5067 5068 exit: 5069 SOC_FUNC_RETURN; 5070 } 5071 5072 /*Port loopback set\get*/ 5073 int pm8x50_port_loopback_set(int unit, int port, pm_info_t pm_info, 5074 portmod_loopback_mode_t loopback_type, int enable) 5075 { 5076 phymod_loopback_mode_t phymod_lb_type; 5077 int nof_phys; 5078 portmod_access_get_params_t params; 5079 phymod_phy_access_t phy_access; 5080 int phy_acc; 5081 SOC_INIT_FUNC_DEFS; 5082 5083 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 5084 5085 /* loopback type validation*/ 5086 switch(loopback_type){ 5087 case portmodLoopbackMacOuter: 5088 _SOC_IF_ERR_EXIT(cdmac_loopback_set(unit, phy_acc, loopback_type, enable)); 5089 break; 5090 case portmodLoopbackPhyRloopPCS: 5091 case portmodLoopbackPhyRloopPMD: 5092 case portmodLoopbackPhyGloopPMD: 5093 case portmodLoopbackPhyGloopPCS: 5094 if (enable) { 5095 _SOC_IF_ERR_EXIT(cdmac_loopback_set(unit, phy_acc, portmodLoopbackMacOuter, 0)); 5096 } 5097 _SOC_IF_ERR_EXIT(portmod_commmon_portmod_to_phymod_loopback_type(unit, 5098 loopback_type, &phymod_lb_type)); 5099 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5100 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5101 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5102 _SOC_IF_ERR_EXIT(phymod_phy_loopback_set(&phy_access, phymod_lb_type, enable)); 5103 break; 5104 default: 5105 _SOC_EXIT_WITH_ERR(SOC_E_UNAVAIL, ( 5106 _SOC_MSG("unsupported loopback type %d"), loopback_type)); 5107 break; 5108 } 5109 5110 if (enable) { 5111 _SOC_IF_ERR_EXIT(pm8x50_port_lag_failover_status_toggle(unit, port, pm_info)); 5112 } 5113 5114 exit: 5115 SOC_FUNC_RETURN; 5116 } 5117 5118 int pm8x50_port_loopback_get(int unit, int port, pm_info_t pm_info, 5119 portmod_loopback_mode_t loopback_type, 5120 int* enable) 5121 { 5122 phymod_loopback_mode_t phymod_lb_type; 5123 portmod_access_get_params_t params; 5124 int nof_phys; 5125 phymod_phy_access_t phy_access; 5126 uint32 tmp_enable = 0; 5127 int rv = PHYMOD_E_NONE; 5128 5129 SOC_INIT_FUNC_DEFS; 5130 5131 switch(loopback_type){ 5132 case portmodLoopbackMacOuter: 5133 _SOC_IF_ERR_EXIT(cdmac_loopback_get(unit, port, loopback_type, enable)); 5134 break; 5135 case portmodLoopbackPhyRloopPCS: 5136 case portmodLoopbackPhyRloopPMD: 5137 case portmodLoopbackPhyGloopPMD: 5138 case portmodLoopbackPhyGloopPCS: 5139 _SOC_IF_ERR_EXIT(portmod_commmon_portmod_to_phymod_loopback_type(unit, 5140 loopback_type, &phymod_lb_type)); 5141 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5142 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5143 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5144 rv = phymod_phy_loopback_get(&phy_access, phymod_lb_type, &tmp_enable); 5145 if (rv == PHYMOD_E_UNAVAIL) { 5146 rv = PHYMOD_E_NONE; 5147 tmp_enable = 0; 5148 } 5149 _SOC_IF_ERR_EXIT(rv); 5150 *enable = tmp_enable; 5151 break; 5152 default: 5153 (*enable) = 0; /* not supported --> no loopback */ 5154 break; 5155 } 5156 5157 exit: 5158 SOC_FUNC_RETURN; 5159 } 5160 5161 /*Port RX MAC ENABLE set\get*/ 5162 int pm8x50_port_rx_mac_enable_set(int unit, int port, 5163 pm_info_t pm_info, int enable) 5164 { 5165 SOC_INIT_FUNC_DEFS; 5166 5167 _SOC_IF_ERR_EXIT(cdmac_rx_enable_set(unit, port, enable)); 5168 exit: 5169 SOC_FUNC_RETURN; 5170 } 5171 5172 int pm8x50_port_rx_mac_enable_get(int unit, int port, 5173 pm_info_t pm_info, int* enable) 5174 { 5175 SOC_INIT_FUNC_DEFS; 5176 5177 _SOC_IF_ERR_EXIT(cdmac_rx_enable_get(unit, port, enable)); 5178 exit: 5179 SOC_FUNC_RETURN; 5180 } 5181 5182 /*Port TX MAC ENABLE set\get*/ 5183 int pm8x50_port_tx_mac_enable_set(int unit, int port, 5184 pm_info_t pm_info, 5185 int enable) 5186 { 5187 SOC_INIT_FUNC_DEFS; 5188 5189 _SOC_IF_ERR_EXIT(cdmac_tx_enable_set(unit, port, enable)); 5190 5191 exit: 5192 SOC_FUNC_RETURN; 5193 } 5194 5195 int pm8x50_port_tx_mac_enable_get(int unit, int port, 5196 pm_info_t pm_info, 5197 int* enable) 5198 { 5199 SOC_INIT_FUNC_DEFS; 5200 5201 _SOC_IF_ERR_EXIT(cdmac_tx_enable_get(unit, port, enable)); 5202 5203 exit: 5204 SOC_FUNC_RETURN; 5205 } 5206 5207 /* 5208 * This API looks at the current port's number of lanes and max speed, 5209 * returns the complete list of force-speed abilities with the same number 5210 * of lanes and speed that is <= max speed, and the complete list of autoneg 5211 * abilities with number of lanes <= current port's number of lanes and 5212 * speed <= max speed. 5213 */ 5214 int pm8x50_port_speed_ability_local_get(int unit, int port, pm_info_t pm_info, 5215 int max_num_abilities, 5216 portmod_port_speed_ability_t* abilities, 5217 int* num_abilities) 5218 { 5219 phymod_phy_access_t phy_access; 5220 portmod_access_get_params_t params; 5221 int nof_phys, port_num_lanes, i; 5222 int port_index, max_speed; 5223 uint32 bitmap; 5224 uint32_t port_lane_mask; 5225 pm8x50_fs_ability_table_entry_t fs_table_entry; 5226 pm8x50_an_ability_table_entry_t an_table_entry; 5227 SOC_INIT_FUNC_DEFS; 5228 5229 *num_abilities = 0; 5230 5231 /* find the max speed of the port */ 5232 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get (unit, port, pm_info, &port_index, &bitmap)); 5233 _SOC_IF_ERR_EXIT(PM8x50_MAX_SPEED_GET(unit, pm_info, &max_speed, port_index)); 5234 5235 /* find number of lanes of the port */ 5236 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5237 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5238 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5239 port_lane_mask = phy_access.access.lane_mask; 5240 PORTMOD_BIT_COUNT(port_lane_mask, port_num_lanes); 5241 5242 for (i = 0; i < PM8x50_FS_ABILITY_TABLE_SIZE; i++) { 5243 _SOC_IF_ERR_EXIT 5244 (_pm8x50_fs_ability_table_read_entry(i, &fs_table_entry)); 5245 5246 if (fs_table_entry.num_lanes == port_num_lanes && fs_table_entry.speed <= max_speed) { 5247 if (*num_abilities < max_num_abilities) { 5248 abilities[*num_abilities].speed = fs_table_entry.speed; 5249 abilities[*num_abilities].num_lanes = fs_table_entry.num_lanes; 5250 abilities[*num_abilities].fec_type = fs_table_entry.fec_type; 5251 abilities[*num_abilities].medium = PORTMOD_PORT_PHY_MEDIUM_ALL; 5252 abilities[*num_abilities].pause = PORTMOD_PORT_PHY_PAUSE_ALL; 5253 abilities[*num_abilities].channel = PORTMOD_PORT_PHY_CHANNEL_ALL; 5254 abilities[*num_abilities].an_mode = PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_NONE; 5255 (*num_abilities) += 1; 5256 } else { 5257 break; 5258 } 5259 } 5260 } 5261 5262 for (i = 0; i < PM8x50_AN_ABILITY_TABLE_SIZE; i++) { 5263 _SOC_IF_ERR_EXIT 5264 (_pm8x50_an_ability_table_read_entry(i, &an_table_entry)); 5265 if ((an_table_entry.num_lanes <= port_num_lanes) && 5266 ( an_table_entry.speed <= max_speed)) { 5267 if (*num_abilities < max_num_abilities) { 5268 abilities[*num_abilities].speed = an_table_entry.speed; 5269 abilities[*num_abilities].num_lanes = an_table_entry.num_lanes; 5270 abilities[*num_abilities].fec_type = an_table_entry.fec_type; 5271 if (an_table_entry.speed == 10000) { 5272 /* 10G AN only support Backplane */ 5273 abilities[*num_abilities].medium = PORTMOD_PORT_PHY_MEDIUM_BACKPLANE; 5274 } else { 5275 abilities[*num_abilities].medium = PORTMOD_PORT_PHY_MEDIUM_ALL; 5276 } 5277 abilities[*num_abilities].pause = PORTMOD_PORT_PHY_PAUSE_ALL; 5278 abilities[*num_abilities].channel = PORTMOD_PORT_PHY_CHANNEL_ALL; 5279 abilities[*num_abilities].an_mode = an_table_entry.an_mode; 5280 (*num_abilities) += 1; 5281 } else { 5282 break; 5283 } 5284 } 5285 } 5286 5287 exit: 5288 SOC_FUNC_RETURN; 5289 } 5290 5291 /* Translate portmod_port_speed_ability_t to phymod_autoneg_advert_abilities_t */ 5292 int _pm8x50_port_port_to_phy_ability(int num_abilities, 5293 const portmod_port_speed_ability_t* abilities, 5294 phymod_autoneg_advert_abilities_t* an_advert_abilities) 5295 { 5296 int i; 5297 5298 an_advert_abilities->num_abilities = num_abilities; 5299 for (i = 0; i < num_abilities; i++) { 5300 an_advert_abilities->autoneg_abilities[i].speed = abilities[i].speed; 5301 an_advert_abilities->autoneg_abilities[i].resolved_num_lanes = abilities[i].num_lanes; 5302 switch (abilities[i].fec_type) { 5303 case PORTMOD_PORT_PHY_FEC_NONE: 5304 an_advert_abilities->autoneg_abilities[i].fec = phymod_fec_None; 5305 break; 5306 case PORTMOD_PORT_PHY_FEC_BASE_R: 5307 an_advert_abilities->autoneg_abilities[i].fec = phymod_fec_CL74; 5308 break; 5309 case PORTMOD_PORT_PHY_FEC_RS_FEC: 5310 an_advert_abilities->autoneg_abilities[i].fec = phymod_fec_CL91; 5311 break; 5312 case PORTMOD_PORT_PHY_FEC_RS_544: 5313 an_advert_abilities->autoneg_abilities[i].fec = phymod_fec_RS544; 5314 break; 5315 case PORTMOD_PORT_PHY_FEC_RS_544_2XN: 5316 an_advert_abilities->autoneg_abilities[i].fec = phymod_fec_RS544_2XN; 5317 break; 5318 default: 5319 return SOC_E_CONFIG; 5320 } 5321 switch (abilities[i].pause) { 5322 case PORTMOD_PORT_PHY_PAUSE_NONE: 5323 an_advert_abilities->autoneg_abilities[i].pause = phymod_pause_none; 5324 break; 5325 case PORTMOD_PORT_PHY_PAUSE_TX: 5326 an_advert_abilities->autoneg_abilities[i].pause = phymod_pause_asym; 5327 break; 5328 case PORTMOD_PORT_PHY_PAUSE_RX: 5329 an_advert_abilities->autoneg_abilities[i].pause = phymod_pause_asym_symm; 5330 break; 5331 case PORTMOD_PORT_PHY_PAUSE_SYMM: 5332 an_advert_abilities->autoneg_abilities[i].pause = phymod_pause_symm; 5333 break; 5334 default: 5335 return SOC_E_CONFIG; 5336 } 5337 switch (abilities[i].an_mode) { 5338 case PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73: 5339 an_advert_abilities->autoneg_abilities[i].an_mode = phymod_AN_MODE_CL73; 5340 break; 5341 case PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM: 5342 an_advert_abilities->autoneg_abilities[i].an_mode = phymod_AN_MODE_CL73BAM; 5343 break; 5344 case PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA: 5345 an_advert_abilities->autoneg_abilities[i].an_mode = phymod_AN_MODE_MSA; 5346 break; 5347 default: 5348 return SOC_E_CONFIG; 5349 } 5350 if (abilities[i].medium == PORTMOD_PORT_PHY_MEDIUM_COPPER) { 5351 an_advert_abilities->autoneg_abilities[i].medium = phymodFirmwareMediaTypeCopperCable; 5352 } else { 5353 an_advert_abilities->autoneg_abilities[i].medium = phymodFirmwareMediaTypePcbTraceBackPlane; 5354 } 5355 if (abilities[i].channel == PORTMOD_PORT_PHY_CHANNEL_SHORT) { 5356 an_advert_abilities->autoneg_abilities[i].channel = phymod_channel_short; 5357 } else { 5358 an_advert_abilities->autoneg_abilities[i].channel = phymod_channel_long; 5359 } 5360 } 5361 5362 return SOC_E_NONE; 5363 } 5364 5365 /* Translate phymod_autoneg_advert_abilities_t to portmod_port_speed_ability_t */ 5366 int _pm8x50_port_phy_to_port_ability(phymod_autoneg_advert_abilities_t* an_advert_abilities, 5367 int* num_abilities, 5368 portmod_port_speed_ability_t* abilities) 5369 { 5370 int i; 5371 5372 *num_abilities = an_advert_abilities->num_abilities; 5373 for (i = 0; i < *num_abilities; i++) { 5374 abilities[i].speed = an_advert_abilities->autoneg_abilities[i].speed; 5375 abilities[i].num_lanes = an_advert_abilities->autoneg_abilities[i].resolved_num_lanes; 5376 switch (an_advert_abilities->autoneg_abilities[i].fec) { 5377 case phymod_fec_None: 5378 abilities[i].fec_type = PORTMOD_PORT_PHY_FEC_NONE; 5379 break; 5380 case phymod_fec_CL74: 5381 abilities[i].fec_type = PORTMOD_PORT_PHY_FEC_BASE_R; 5382 break; 5383 case phymod_fec_CL91: 5384 abilities[i].fec_type = PORTMOD_PORT_PHY_FEC_RS_FEC; 5385 break; 5386 case phymod_fec_RS544: 5387 abilities[i].fec_type = PORTMOD_PORT_PHY_FEC_RS_544; 5388 break; 5389 case phymod_fec_RS544_2XN: 5390 abilities[i].fec_type = PORTMOD_PORT_PHY_FEC_RS_544_2XN; 5391 break; 5392 default: 5393 return SOC_E_CONFIG; 5394 } 5395 switch (an_advert_abilities->autoneg_abilities[i].pause) { 5396 case phymod_pause_none: 5397 abilities[i].pause = PORTMOD_PORT_PHY_PAUSE_NONE; 5398 break; 5399 case phymod_pause_asym: 5400 abilities[i].pause = PORTMOD_PORT_PHY_PAUSE_TX; 5401 break; 5402 case phymod_pause_asym_symm: 5403 abilities[i].pause = PORTMOD_PORT_PHY_PAUSE_RX; 5404 break; 5405 case phymod_pause_symm: 5406 abilities[i].pause = PORTMOD_PORT_PHY_PAUSE_SYMM; 5407 break; 5408 default: 5409 return SOC_E_CONFIG; 5410 } 5411 switch (an_advert_abilities->autoneg_abilities[i].an_mode) { 5412 case phymod_AN_MODE_CL73: 5413 abilities[i].an_mode = PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73; 5414 break; 5415 case phymod_AN_MODE_CL73BAM: 5416 abilities[i].an_mode = PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM; 5417 break; 5418 case phymod_AN_MODE_MSA: 5419 abilities[i].an_mode = PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA; 5420 break; 5421 default: 5422 return SOC_E_CONFIG; 5423 } 5424 if (an_advert_abilities->autoneg_abilities[i].medium == phymodFirmwareMediaTypeCopperCable) { 5425 abilities[i].medium = PORTMOD_PORT_PHY_MEDIUM_COPPER; 5426 } else { 5427 abilities[i].medium = PORTMOD_PORT_PHY_MEDIUM_BACKPLANE; 5428 } 5429 if (an_advert_abilities->autoneg_abilities[i].channel == phymod_channel_short) { 5430 abilities[i].channel = PORTMOD_PORT_PHY_CHANNEL_SHORT; 5431 } else { 5432 abilities[i].channel = PORTMOD_PORT_PHY_CHANNEL_LONG; 5433 } 5434 } 5435 5436 return SOC_E_NONE; 5437 } 5438 5439 /*Set/get port auto negotiation ability*/ 5440 int pm8x50_port_autoneg_ability_advert_set(int unit, int port, pm_info_t pm_info, 5441 int num_abilities, 5442 const portmod_port_speed_ability_t* abilities) 5443 { 5444 portmod_access_get_params_t params; 5445 phymod_phy_access_t phy_access, phy_copy; 5446 int nof_phys, i, port_index, mpp_index; 5447 uint32 bitmap, flags = 0; 5448 portmod_vco_type_t request_vco = 0; 5449 pm8x50_vcos_bmp_t vcos = 0; 5450 portmod_pm_vco_setting_t vco_setting; 5451 portmod_speed_config_t speed_config; 5452 portmod_pbmp_t ports; 5453 phymod_autoneg_advert_ability_t autoneg_abilities[PM8x50_MAX_AN_ABILITY]; 5454 phymod_autoneg_advert_abilities_t an_advert_abilities; 5455 int is_msa = 0, is_bam = 0, current_media_type = 0; 5456 int is_dual_50g = 0, pam4_req = 0, cl73_bam_msa_base_r_req = 0, dual_50g_req = 0; 5457 int rs544_req = 0, rs528_req = 0; 5458 phymod_an_mode_type_t an_mode = 0, cur_an_mode = 0; 5459 int channel_25g = 0, flag; 5460 int fec_cl73, fec_cl73_25g, fec_cl73bam_msa, fec_rs528_bam_msa; 5461 phymod_phy_pll_state_t old_pll_state, new_pll_state; 5462 uint8 pll_lanes_bitmap, rs528_bm = 0, rs544_bm = 0, rs272_bm = 0, affected_bm = 0; 5463 phymod_firmware_lane_config_t fw_lane_config; 5464 int tvco_pll_index, ovco_pll_index; 5465 portmod_fec_t fec; 5466 pm_version_t version; 5467 5468 SOC_INIT_FUNC_DEFS; 5469 5470 fec_cl73 = PORTMOD_PORT_PHY_FEC_INVALID; 5471 fec_cl73_25g = PORTMOD_PORT_PHY_FEC_INVALID; 5472 fec_cl73bam_msa = PORTMOD_PORT_PHY_FEC_INVALID; 5473 fec_rs528_bam_msa = PORTMOD_PORT_PHY_FEC_INVALID; 5474 5475 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5476 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5477 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5478 5479 /* 1. Valid media type */ 5480 _SOC_IF_ERR_EXIT( 5481 phymod_phy_firmware_lane_config_get(&phy_access, &fw_lane_config)); 5482 5483 if (fw_lane_config.MediaType == phymodFirmwareMediaTypeCopperCable) { 5484 current_media_type = PORTMOD_PORT_PHY_MEDIUM_COPPER; 5485 } else if (fw_lane_config.MediaType == phymodFirmwareMediaTypePcbTraceBackPlane) { 5486 current_media_type = PORTMOD_PORT_PHY_MEDIUM_BACKPLANE; 5487 } 5488 5489 /* 2. Validate abilities */ 5490 for (i = 0; i < num_abilities; i++) { 5491 is_dual_50g = 0; 5492 _SOC_IF_ERR_EXIT(_pm8x50_an_ability_table_vco_get(abilities[i].speed, abilities[i].num_lanes, 5493 abilities[i].fec_type, abilities[i].an_mode, &request_vco)); 5494 if (abilities[i].speed / abilities[i].num_lanes > NRZ_MAX_PER_LANE_SPEED) { 5495 pam4_req = 1; 5496 } 5497 /* 2.1. AN ability is supported by HW */ 5498 if (request_vco == portmodVCOInvalid) { 5499 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 5500 (_SOC_MSG("port %d: abilities[%d] is not supported."), port, i)); 5501 } 5502 if ((abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_544) || 5503 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_544_2XN)) { 5504 rs544_req = 1; 5505 } else if (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_FEC) { 5506 rs528_req = 1; 5507 } 5508 5509 /* 2.2. AN abilities do not conflict with each other */ 5510 if (abilities[i].pause != abilities[0].pause) { 5511 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5512 (_SOC_MSG("port %d: Pause conflicts among abilities."), port)); 5513 } 5514 if (abilities[i].medium != current_media_type) { 5515 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5516 (_SOC_MSG("port %d: Medium conflicts with current media type."), port)); 5517 } 5518 if ((abilities[i].speed == 50000) && 5519 (abilities[i].num_lanes == 2) && 5520 (abilities[i].fec_type != PORTMOD_PORT_PHY_FEC_RS_544)) { 5521 is_dual_50g = 1; 5522 dual_50g_req = 1; 5523 } 5524 if (abilities[i].an_mode == PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_BAM) { 5525 is_bam = 1; 5526 /* CL74 request of 20G-1lane, 25G-1lane, 40G-2lane should be identical */ 5527 if (abilities[i].speed < 50000) { 5528 if (((fec_cl73bam_msa == PORTMOD_PORT_PHY_FEC_NONE) 5529 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R)) || 5530 ((fec_cl73bam_msa == PORTMOD_PORT_PHY_FEC_BASE_R) 5531 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE))) { 5532 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5533 (_SOC_MSG("port %d: FEC conflicts among abilities."), port)); 5534 } else { 5535 /* only BaseR and FEC_NONE are considered here */ 5536 if ((abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R) || 5537 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE)) { 5538 fec_cl73bam_msa = abilities[i].fec_type; 5539 } 5540 if (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R) { 5541 cl73_bam_msa_base_r_req = 1; 5542 } 5543 } 5544 } 5545 /* RS528 request of 25G-1lane, 50G-2lane should be identical */ 5546 if ((abilities[i].speed == 25000) || (is_dual_50g)) { 5547 if (((fec_rs528_bam_msa == PORTMOD_PORT_PHY_FEC_NONE) 5548 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_FEC)) || 5549 ((fec_rs528_bam_msa == PORTMOD_PORT_PHY_FEC_RS_FEC) 5550 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE))) { 5551 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5552 (_SOC_MSG("port %d: FEC conflicts among abilities."), port)); 5553 } else { 5554 /* only RSFEC and FEC_NONE are considered here */ 5555 if ((abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_FEC) || 5556 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE)) { 5557 fec_rs528_bam_msa = abilities[i].fec_type; 5558 } 5559 } 5560 } 5561 } else if (abilities[i].an_mode == PORTMOD_PORT_PHY_CONTROL_AUTONEG_MODE_CL73_MSA) { 5562 is_msa = 1; 5563 /* CL74 request of 25G-1lane should be identical */ 5564 if (((fec_cl73bam_msa == PORTMOD_PORT_PHY_FEC_NONE) 5565 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R)) || 5566 ((fec_cl73bam_msa == PORTMOD_PORT_PHY_FEC_BASE_R) 5567 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE))) { 5568 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5569 (_SOC_MSG("port %d: FEC conflicts among abilities."), port)); 5570 } else { 5571 /* only BaseR and FEC_NONE are considered here */ 5572 if ((abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R) || 5573 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE)) { 5574 fec_cl73bam_msa = abilities[i].fec_type; 5575 } 5576 if (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R) { 5577 cl73_bam_msa_base_r_req = 1; 5578 } 5579 } 5580 /* RS528 request of 25G-1lane, 50G-2lane should be identical */ 5581 if (((fec_rs528_bam_msa == PORTMOD_PORT_PHY_FEC_NONE) 5582 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_FEC)) || 5583 ((fec_rs528_bam_msa == PORTMOD_PORT_PHY_FEC_RS_FEC) 5584 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE))) { 5585 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5586 (_SOC_MSG("port %d: FEC conflicts among abilities."), port)); 5587 } else { 5588 /* only RSFEC and FEC_NONE are considered here */ 5589 if ((abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_FEC) || 5590 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE)) { 5591 fec_rs528_bam_msa = abilities[i].fec_type; 5592 } 5593 } 5594 } else { 5595 /* CL73 */ 5596 if (abilities[i].speed == 40000 || abilities[i].speed == 10000) { 5597 if (((fec_cl73 == PORTMOD_PORT_PHY_FEC_NONE) 5598 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R)) || 5599 ((fec_cl73 == PORTMOD_PORT_PHY_FEC_BASE_R) 5600 && (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE))) { 5601 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5602 (_SOC_MSG("port %d: FEC conflicts among abilities."), port)); 5603 } else { 5604 /* only BaseR and FEC_NONE are considered here */ 5605 if ((abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R) || 5606 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_NONE)) { 5607 fec_cl73 = abilities[i].fec_type; 5608 } 5609 /* 50G-2lane shares the same cl74 bit with other CL73,CL73BAM,MSA abilities */ 5610 /* cl73_bam_msa_base_r_req is used to remember if there is any CL73,BAM,MSA BaseR request */ 5611 if (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_BASE_R) { 5612 cl73_bam_msa_base_r_req = 1; 5613 } 5614 } 5615 if (abilities[i].speed == 10000) { 5616 if (abilities[i].medium != PORTMOD_PORT_PHY_MEDIUM_BACKPLANE) { 5617 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 5618 (_SOC_MSG("port %d: abilities[%d] is not supported."), port, i)); 5619 } 5620 } 5621 } else if (abilities[i].speed == 25000) { 5622 if (!channel_25g) { 5623 channel_25g = abilities[i].channel; 5624 } else { 5625 if (channel_25g != abilities[i].channel) { 5626 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5627 (_SOC_MSG("port %d: Channel conflicts among abilities."), port)); 5628 } 5629 } 5630 if ((abilities[i].channel == PORTMOD_PORT_PHY_CHANNEL_SHORT) && 5631 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_FEC)) { 5632 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 5633 (_SOC_MSG("port %d: abilities[%d] is not supported."), port, i)); 5634 } 5635 if ((fec_cl73_25g == PORTMOD_PORT_PHY_FEC_NONE) 5636 && (abilities[i].fec_type != PORTMOD_PORT_PHY_FEC_NONE)) { 5637 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5638 (_SOC_MSG("port %d: FEC conflicts among abilities."), port)); 5639 } else { 5640 fec_cl73_25g = abilities[i].fec_type; 5641 } 5642 } 5643 } 5644 if (request_vco == portmodVCO20P625G) { 5645 PM8x50_VCO_ETH_20P625G_SET(vcos); 5646 } else if (request_vco == portmodVCO25P781G) { 5647 PM8x50_VCO_ETH_25P781G_SET(vcos); 5648 } else if (request_vco == portmodVCO26P562G) { 5649 PM8x50_VCO_ETH_26P562G_SET(vcos); 5650 } 5651 } 5652 5653 /* 50G-2lane does not support Base-R. 5654 In AN, 50G-2lane shares the same cl74 bit with other CL73,CL73BAM,MSA abilities. */ 5655 if (dual_50g_req && (cl73_bam_msa_base_r_req == 1)) { 5656 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5657 (_SOC_MSG("port %d: Base_R cannot be advertised together with 50G-2lane abilities."), port)); 5658 } 5659 5660 if (is_bam && is_msa) { 5661 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5662 (_SOC_MSG("port %d: an_mode conflicts among abilities." 5663 "Cannot advertise CL73MSA and CL73BAM at the same time."), port)); 5664 } else if (is_bam) { 5665 an_mode = phymod_AN_MODE_CL73BAM; 5666 } else if (is_msa) { 5667 an_mode = phymod_AN_MODE_CL73_MSA; 5668 } else { 5669 an_mode = phymod_AN_MODE_CL73; 5670 } 5671 5672 /* within same MPP, MSA and BAM can not be exist at same time */ 5673 sal_memcpy(&phy_copy, &phy_access, sizeof(phy_copy)); 5674 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 5675 mpp_index = (int)(port_index / 4); 5676 for (i = (0 + (mpp_index * 4)); i < (4 + (mpp_index*4)); i++) { 5677 if (i == port_index) { 5678 continue; 5679 } 5680 _SOC_IF_ERR_EXIT(PM8x50_AN_MODE_GET(unit, pm_info, &cur_an_mode, i)); 5681 if ((an_mode == phymod_AN_MODE_CL73_MSA) && (cur_an_mode == phymod_AN_MODE_CL73BAM)) { 5682 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5683 (_SOC_MSG("port %d: CL73_MSA cannot be advertised when current MPP is in CL73_BAM."), port)); 5684 } 5685 if ((an_mode == phymod_AN_MODE_CL73BAM) && (cur_an_mode == phymod_AN_MODE_CL73_MSA)) { 5686 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5687 (_SOC_MSG("port %d: CL73_BAM cannot be advertised when current MPP is in CL73_MSA."), port)); 5688 } 5689 } 5690 5691 /* 2.3. FEC arch can be supported within the each MPP */ 5692 if (rs544_req || rs528_req) { 5693 _SOC_IF_ERR_EXIT(_pm8x50_fec_lanebitmap_get(unit, pm_info, &rs528_bm, &rs544_bm, &rs272_bm)); 5694 rs528_bm &= ~phy_access.access.lane_mask; 5695 rs544_bm &= ~phy_access.access.lane_mask; 5696 rs272_bm &= ~phy_access.access.lane_mask; 5697 if (rs544_req) { 5698 rs544_bm |= phy_access.access.lane_mask; 5699 } 5700 if (rs528_req) { 5701 rs528_bm |= phy_access.access.lane_mask; 5702 } 5703 _SOC_IF_ERR_EXIT(_pm8x50_pm_version_get(unit, pm_info, &version)); 5704 if (version.tech_process == PM_TECH_16NM) { 5705 PM8X50_PM_VERSION_F_REV0_16NM_SET(flags); 5706 } 5707 _SOC_IF_ERR_EXIT(_pm8x50_fec_validate(unit, flags, rs528_bm, rs544_bm, rs272_bm, &affected_bm)); 5708 } 5709 5710 /* 2.4. AN ability can be supported by current VCOs */ 5711 if (pam4_req && (PM_8x50_INFO(pm_info)->tvco == portmodVCO20P625G)) { 5712 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5713 (_SOC_MSG("Can not support Ethernet PAM4 speeds when TVCO is 20.625G."))); 5714 } 5715 5716 _SOC_IF_ERR_EXIT( 5717 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &pll_lanes_bitmap)); 5718 if (pll_lanes_bitmap & phy_access.access.lane_mask) { 5719 /* Current port is using OVCO, so that OVCO can not be changed. */ 5720 flag = PORTMOD_PM_SPEED_VALIDATE_F_PLL_SWITCH_NOT_ALLOWED; 5721 } else { 5722 flag = PORTMOD_PM_SPEED_VALIDATE_F_ONE_PLL_SWITCH_ALLOWED; 5723 } 5724 5725 PORTMOD_PBMP_PORT_SET(ports, port); 5726 _SOC_IF_ERR_EXIT( 5727 _pm8x50_vcos_setting_validate(unit, pm_info, &ports, vcos, flag, &vco_setting)); 5728 5729 an_advert_abilities.autoneg_abilities = autoneg_abilities; 5730 _SOC_IF_ERR_EXIT(_pm8x50_port_port_to_phy_ability(num_abilities, abilities, &an_advert_abilities)); 5731 5732 tvco_pll_index = PM8X50_TVCO_PLL_INDEX_GET(pm_info); 5733 ovco_pll_index = (tvco_pll_index == 1)? 0: 1; 5734 _SOC_IF_ERR_EXIT( 5735 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &pll_lanes_bitmap)); 5736 if (ovco_pll_index == 1) { 5737 old_pll_state.pll1_lanes_bitmap = pll_lanes_bitmap; 5738 } else { 5739 old_pll_state.pll0_lanes_bitmap = pll_lanes_bitmap; 5740 } 5741 5742 _SOC_IF_ERR_EXIT( 5743 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &pll_lanes_bitmap)); 5744 if (tvco_pll_index == 1) { 5745 old_pll_state.pll1_lanes_bitmap = pll_lanes_bitmap; 5746 } else { 5747 old_pll_state.pll0_lanes_bitmap = pll_lanes_bitmap; 5748 } 5749 /* 3. Set AN abilities in HW */ 5750 _SOC_IF_ERR_EXIT( 5751 phymod_phy_autoneg_advert_ability_set(&phy_access, &an_advert_abilities, &old_pll_state, &new_pll_state)); 5752 5753 /* 4. Update DB and WB */ 5754 if (vco_setting.is_ovco_new) { 5755 PM_8x50_INFO(pm_info)->ovco = vco_setting.ovco; 5756 } 5757 5758 /* 4.1. Update an_mode in WB */ 5759 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get (unit, port, pm_info, &port_index, &bitmap)); 5760 _SOC_IF_ERR_EXIT(PM8x50_AN_MODE_SET(unit, pm_info, an_mode, port_index)); 5761 5762 /* 4.2. Update FEC type in WB for RS528, RS544 case */ 5763 /* If AN request RS544, update DB and this will be treated as FEC arch restriction. 5764 * Else if PM is 16nm and AN request RS528, update DB and this will be treated as FEC arch restriction. 5765 * Else if AN request other FEC, keep the force speed FEC restriction. Need to update 5766 * FEC restrition when AN is enabled. 5767 */ 5768 if (rs544_req) { 5769 fec = PORTMOD_PORT_PHY_FEC_RS_544; 5770 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 5771 if ((phy_access.access.lane_mask >> i) & 0x1) { 5772 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, fec)); 5773 } 5774 } 5775 } else if (rs528_req && PM8X50_PM_VERSION_F_REV0_16NM_GET(flags)) { 5776 fec = PORTMOD_PORT_PHY_FEC_RS_FEC; 5777 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 5778 if ((phy_access.access.lane_mask >> i) & 0x1) { 5779 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, fec)); 5780 } 5781 } 5782 } else { 5783 /* Call speed_config_get to get the FEC type and update the WB */ 5784 /* This is to make sure the DB stores the FS FEC instead of the previous adv FEC */ 5785 _SOC_IF_ERR_EXIT(pm8x50_port_speed_config_get(unit, port, pm_info, &speed_config)); 5786 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 5787 if ((phy_access.access.lane_mask >> i) & 0x1) { 5788 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, speed_config.fec)); 5789 } 5790 } 5791 } 5792 5793 /* 4.3. Update PLL lane bit maps in WB, power down OVCO if it's free */ 5794 _SOC_IF_ERR_EXIT( 5795 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &pll_lanes_bitmap)); 5796 if (tvco_pll_index == 1) { 5797 /* Power down OVCO if it's not being used */ 5798 if (!(pll_lanes_bitmap || new_pll_state.pll0_lanes_bitmap)) { 5799 _SOC_IF_ERR_EXIT(phymod_phy_pll_pwrdn(&phy_access, ovco_pll_index, 1)); 5800 PM_8x50_INFO(pm_info)->ovco = portmodVCOInvalid; 5801 } 5802 pll_lanes_bitmap = (uint8) new_pll_state.pll0_lanes_bitmap; 5803 _SOC_IF_ERR_EXIT( 5804 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, pll_lanes_bitmap)); 5805 pll_lanes_bitmap = (uint8) new_pll_state.pll1_lanes_bitmap; 5806 _SOC_IF_ERR_EXIT( 5807 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, pll_lanes_bitmap)); 5808 } else { 5809 /* Power down OVCO if it's not being used */ 5810 if (!(pll_lanes_bitmap || new_pll_state.pll1_lanes_bitmap)) { 5811 _SOC_IF_ERR_EXIT(phymod_phy_pll_pwrdn(&phy_access, ovco_pll_index, 1)); 5812 PM_8x50_INFO(pm_info)->ovco = portmodVCOInvalid; 5813 } 5814 pll_lanes_bitmap = (uint8) new_pll_state.pll0_lanes_bitmap; 5815 _SOC_IF_ERR_EXIT( 5816 PM8x50_TVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, pll_lanes_bitmap)); 5817 pll_lanes_bitmap = (uint8) new_pll_state.pll1_lanes_bitmap; 5818 _SOC_IF_ERR_EXIT( 5819 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_SET(unit, pm_info, pll_lanes_bitmap)); 5820 } 5821 5822 exit: 5823 SOC_FUNC_RETURN; 5824 } 5825 5826 int pm8x50_port_autoneg_ability_advert_get(int unit, int port, pm_info_t pm_info, 5827 int max_num_abilities, 5828 portmod_port_speed_ability_t* abilities, 5829 int* actual_num_abilities) 5830 { 5831 portmod_access_get_params_t params; 5832 phymod_phy_access_t phy_access; 5833 int nof_phys, i; 5834 phymod_autoneg_advert_ability_t autoneg_abilities[PM8x50_MAX_AN_ABILITY]; 5835 phymod_autoneg_advert_abilities_t an_advert_abilities; 5836 5837 SOC_INIT_FUNC_DEFS; 5838 5839 for (i = 0; i < PM8x50_MAX_AN_ABILITY; i++) { 5840 _SOC_IF_ERR_EXIT(phymod_autoneg_advert_ability_t_init(&autoneg_abilities[i])); 5841 } 5842 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5843 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5844 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5845 an_advert_abilities.autoneg_abilities = autoneg_abilities; 5846 _SOC_IF_ERR_EXIT(phymod_phy_autoneg_advert_ability_get(&phy_access, &an_advert_abilities)); 5847 5848 if (an_advert_abilities.num_abilities > max_num_abilities) { 5849 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5850 (_SOC_MSG("port %d: There are %d AN abilities. Larger array is needed."), 5851 port, an_advert_abilities.num_abilities)); 5852 } else { 5853 _SOC_IF_ERR_EXIT(_pm8x50_port_phy_to_port_ability(&an_advert_abilities, actual_num_abilities, abilities)); 5854 } 5855 5856 exit: 5857 SOC_FUNC_RETURN; 5858 } 5859 5860 /*Port ability remote Adv get*/ 5861 int pm8x50_port_autoneg_ability_remote_get(int unit, int port, pm_info_t pm_info, 5862 int max_num_abilities, 5863 portmod_port_speed_ability_t* abilities, 5864 int* actual_num_abilities) 5865 { 5866 portmod_access_get_params_t params; 5867 phymod_phy_access_t phy_access; 5868 int nof_phys, i; 5869 phymod_autoneg_advert_ability_t autoneg_abilities[PM8x50_MAX_AN_ABILITY]; 5870 phymod_autoneg_advert_abilities_t an_advert_abilities; 5871 int port_index, is_400g_an = 0, remote_pause = 0; 5872 uint32 bitmap; 5873 phymod_autoneg_status_t an_status; 5874 5875 SOC_INIT_FUNC_DEFS; 5876 5877 for (i = 0; i < PM8x50_MAX_AN_ABILITY; i++) { 5878 _SOC_IF_ERR_EXIT(phymod_autoneg_advert_ability_t_init(&autoneg_abilities[i])); 5879 } 5880 5881 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5882 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5883 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5884 an_advert_abilities.autoneg_abilities = autoneg_abilities; 5885 5886 _SOC_IF_ERR_EXIT(phymod_phy_autoneg_remote_advert_ability_get(&phy_access, &an_advert_abilities)); 5887 5888 /* next need to check 400G AN enabled or not */ 5889 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 5890 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_GET(unit, pm_info, &is_400g_an, port_index)); 5891 _SOC_IF_ERR_EXIT(pm8x50_port_autoneg_status_get(unit, port, pm_info, &an_status)); 5892 if (is_400g_an && an_status.enabled && an_status.locked) { 5893 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_REMOTE_PAUSE_GET(unit, pm_info, &remote_pause, port_index)); 5894 an_advert_abilities.num_abilities = 1; 5895 an_advert_abilities.autoneg_abilities[0].pause = remote_pause; 5896 an_advert_abilities.autoneg_abilities[0].speed = 400000; 5897 an_advert_abilities.autoneg_abilities[0].resolved_num_lanes = 8; 5898 an_advert_abilities.autoneg_abilities[0].fec = phymod_fec_RS544_2XN; 5899 an_advert_abilities.autoneg_abilities[0].channel = phymod_channel_long; 5900 an_advert_abilities.autoneg_abilities[0].an_mode = phymod_AN_MODE_MSA; 5901 } 5902 5903 if (an_advert_abilities.num_abilities > max_num_abilities) { 5904 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 5905 (_SOC_MSG("port %d: There are %d AN abilities. Larger array is needed."), 5906 port, an_advert_abilities.num_abilities)); 5907 } else { 5908 _SOC_IF_ERR_EXIT(_pm8x50_port_phy_to_port_ability(&an_advert_abilities, actual_num_abilities, abilities)); 5909 } 5910 5911 exit: 5912 SOC_FUNC_RETURN; 5913 } 5914 5915 /*Set\Get autoneg*/ 5916 int pm8x50_port_autoneg_set(int unit, int port, pm_info_t pm_info, 5917 uint32 phy_flags, 5918 const phymod_autoneg_control_t* an) 5919 { 5920 portmod_access_get_params_t params; 5921 phymod_phy_access_t phy_access; 5922 int nof_phys, port_num_lanes; 5923 int port_index, actual_num_abilities = 0, rs544_req = 0, rs528_req = 0, is_400g_an = 0; 5924 uint32_t bitmap; 5925 phymod_autoneg_control_t an_control; 5926 uint8_t pll_lanes_bitmap; 5927 int tvco_pll_index, ovco_pll_index, i; 5928 portmod_port_speed_ability_t abilities[PM8x50_MAX_AN_ABILITY]; 5929 portmod_fec_t fec; 5930 pm_version_t version; 5931 SOC_INIT_FUNC_DEFS; 5932 5933 _SOC_IF_ERR_EXIT(_pm8x50_pm_version_get(unit, pm_info, &version)); 5934 5935 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 5936 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 5937 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 5938 ¶ms, 1, &phy_access, &nof_phys, NULL)); 5939 PORTMOD_BIT_COUNT(phy_access.access.lane_mask, port_num_lanes); 5940 tvco_pll_index = PM8X50_TVCO_PLL_INDEX_GET(pm_info); 5941 ovco_pll_index = (tvco_pll_index == 1)? 0: 1; 5942 5943 an_control = *an; 5944 5945 an_control.num_lane_adv = port_num_lanes; 5946 5947 /* Get an_mode from WB */ 5948 _SOC_IF_ERR_EXIT(PM8x50_AN_MODE_GET(unit, pm_info, &an_control.an_mode, port_index)); 5949 if (an_control.an_mode == phymod_AN_MODE_NONE) { 5950 /* Return error only when user want to enable AN without any AN abilities being advertised. */ 5951 if (!an_control.enable) { 5952 an_control.an_mode = phymod_AN_MODE_CL73; 5953 } else { 5954 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 5955 (_SOC_MSG("port %d: There's no valid AN advertisement for the port."), port)); 5956 } 5957 } 5958 5959 if (an_control.enable) { 5960 /* Check if RS544 is required for AN abilities */ 5961 _SOC_IF_ERR_EXIT(pm8x50_port_autoneg_ability_advert_get(unit, port, pm_info, 5962 PM8x50_MAX_AN_ABILITY, 5963 abilities, 5964 &actual_num_abilities)); 5965 for (i = 0; i < actual_num_abilities; i++) { 5966 /* check if 400G an is enabled */ 5967 if (abilities[i].speed == 400000) { 5968 is_400g_an = 1; 5969 } 5970 if ((abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_544) || 5971 (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_544_2XN)) { 5972 rs544_req = 1; 5973 } 5974 if (abilities[i].fec_type == PORTMOD_PORT_PHY_FEC_RS_FEC) { 5975 rs528_req = 1; 5976 } 5977 } 5978 if (rs544_req || (rs528_req && version.tech_process == PM_TECH_16NM)) { 5979 PHYMOD_AN_F_FEC_RS272_CLR_SET(&an_control); 5980 } 5981 } 5982 /* 5983 * Before enabling serdes AN bit, need to disable the port in PCS 5984 * and update mac port mode. 5985 */ 5986 if (an_control.enable) { 5987 _SOC_IF_ERR_EXIT(phymod_phy_pcs_enable_set(&phy_access, 0)); 5988 /* call port level port mode update */ 5989 _SOC_IF_ERR_EXIT(_pm8x50_pm_port_mode_update(unit, port, pm_info, port_index, 1)); 5990 } 5991 5992 _SOC_IF_ERR_EXIT(phymod_phy_autoneg_set(&phy_access, &an_control)); 5993 5994 if (an_control.enable) { 5995 /* When AN is enable on a port, always connect that port to TVCO */ 5996 _SOC_IF_ERR_EXIT( 5997 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &pll_lanes_bitmap)); 5998 pll_lanes_bitmap &= ~phy_access.access.lane_mask; 5999 _SOC_IF_ERR_EXIT( 6000 PM8x50_OVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, pll_lanes_bitmap)); 6001 6002 /* If OVCO is not being used, power down OVCO */ 6003 if (!pll_lanes_bitmap) { 6004 _SOC_IF_ERR_EXIT( 6005 PM8x50_OVCO_PLL_ADV_LANE_BITMAP_GET(unit, pm_info, &pll_lanes_bitmap)); 6006 if (!pll_lanes_bitmap) { 6007 _SOC_IF_ERR_EXIT(phymod_phy_pll_pwrdn(&phy_access, ovco_pll_index, 1)); 6008 PM_8x50_INFO(pm_info)->ovco = portmodVCOInvalid; 6009 } 6010 } 6011 6012 _SOC_IF_ERR_EXIT( 6013 PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_GET(unit, pm_info, &pll_lanes_bitmap)); 6014 pll_lanes_bitmap |= phy_access.access.lane_mask; 6015 _SOC_IF_ERR_EXIT( 6016 PM8x50_TVCO_PLL_ACTIVE_LANE_BITMAP_SET(unit, pm_info, pll_lanes_bitmap)); 6017 /* Update FEC usage in WB. 6018 * If AN require RS544, set FEC type to RS544 in WB. 6019 * Else if AN requrie RS528, set FEC type to RS528 in WB. 6020 * Otherwise, set to FEC_NONE, indicating the port 6021 * does not have FEC restriction within the MPP. 6022 */ 6023 if (rs544_req) { 6024 fec = PORTMOD_PORT_PHY_FEC_RS_544; 6025 } else if (rs528_req) { 6026 fec = PORTMOD_PORT_PHY_FEC_RS_FEC; 6027 } else { 6028 fec = PORTMOD_PORT_PHY_FEC_NONE; 6029 } 6030 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 6031 if ((phy_access.access.lane_mask >> i) & 0x1) { 6032 _SOC_IF_ERR_EXIT(PM8x50_LANE2FEC_SET(unit, pm_info, i, fec)); 6033 } 6034 } 6035 6036 } 6037 /* update the 400G An enabled */ 6038 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_SET(unit, pm_info, is_400g_an, port_index)); 6039 /* if 400G an enabled, needs to enable call back */ 6040 /* call back register should happen after 400G AN ENABLE is set */ 6041 if (is_400g_an) { 6042 pm8x50_port_400g_an_state_t an_state = PM8X50_PORT_AN_CHECK_PAGE_COMPLETE; 6043 uint32 an_wait_link_count = 0; 6044 /* update the 400G An state */ 6045 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_SET(unit, pm_info, an_state)); 6046 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_WAIT_LINK_COUNT_SET(unit, pm_info, an_wait_link_count)); 6047 _SOC_IF_ERR_EXIT(portmod_port_periodic_callback_register(unit, port, pm8x50_periodic_callback, PORTMOD_THREAD_INTERVAL_1s)); 6048 } 6049 6050 6051 exit: 6052 SOC_FUNC_RETURN; 6053 } 6054 6055 int pm8x50_port_autoneg_get(int unit, int port, pm_info_t pm_info, 6056 uint32 phy_flags, 6057 phymod_autoneg_control_t* an) 6058 { 6059 portmod_access_get_params_t params; 6060 phymod_phy_access_t phy_access; 6061 int nof_phys, port_index, is_400g_an = 0; 6062 uint32 bitmap; 6063 uint32_t an_done; 6064 6065 SOC_INIT_FUNC_DEFS; 6066 6067 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6068 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6069 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6070 _SOC_IF_ERR_EXIT(phymod_phy_autoneg_get(&phy_access, an, &an_done)); 6071 6072 /* next need to check 400G AN enabled or not */ 6073 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 6074 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_GET(unit, pm_info, &is_400g_an, port_index)); 6075 if (is_400g_an) { 6076 an->enable = 1; 6077 an->an_mode = phymod_AN_MODE_CL73_MSA; 6078 } 6079 6080 6081 exit: 6082 SOC_FUNC_RETURN; 6083 } 6084 6085 /*Get autoneg status*/ 6086 int pm8x50_port_autoneg_status_get(int unit, int port, pm_info_t pm_info, 6087 phymod_autoneg_status_t* an_status) 6088 { 6089 portmod_access_get_params_t params; 6090 phymod_phy_access_t phy_access; 6091 int nof_phys, port_index, is_400g_an = 0, an_400g_state; 6092 uint32 bitmap; 6093 6094 SOC_INIT_FUNC_DEFS; 6095 6096 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6097 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6098 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6099 6100 _SOC_IF_ERR_EXIT(phymod_phy_autoneg_status_get(&phy_access, an_status)); 6101 6102 if (!(an_status->enabled && an_status->locked)) { 6103 /* upper layer should not rely on the 6104 * data rate if the AN is not locked 6105 */ 6106 an_status->data_rate = 0; 6107 an_status->interface = SOC_PORT_IF_NULL; 6108 } 6109 /* next need to check 400G AN enabled or not */ 6110 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 6111 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_GET(unit, pm_info, &is_400g_an, port_index)); 6112 if (is_400g_an) { 6113 an_status->data_rate = 400000; 6114 an_status->enabled = 1; 6115 an_status->locked = 0; 6116 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_GET(unit, pm_info, &an_400g_state)); 6117 if (an_400g_state == PM8X50_PORT_AN_COMPLETE) { 6118 an_status->locked = 1; 6119 } 6120 } 6121 6122 exit: 6123 SOC_FUNC_RETURN; 6124 } 6125 6126 /*get link status*/ 6127 int pm8x50_port_link_get(int unit, int port, pm_info_t pm_info, 6128 int flags, int* link) 6129 { 6130 portmod_speed_config_t speed_config; 6131 int latch_val = 0; 6132 uint32 rval, bitmap; 6133 portmod_access_get_params_t params; 6134 phymod_phy_access_t phy_access; 6135 int nof_phys, port_index, is_400g_an = 0, an_400g_state; 6136 6137 SOC_INIT_FUNC_DEFS; 6138 6139 if (SAL_BOOT_SIMULATION){ 6140 *link = 1; 6141 } else { 6142 _SOC_IF_ERR_EXIT(pm8x50_port_speed_config_get(unit, port, pm_info, &speed_config)); 6143 if (speed_config.speed == 400000) { 6144 _SOC_IF_ERR_EXIT( 6145 pm8x50_port_link_latch_down_get(unit, port, pm_info, PORTMOD_PORT_LINK_LATCH_DOWN_F_CLEAR, &latch_val)); 6146 if (latch_val) { 6147 *link = 0; 6148 } else { 6149 _SOC_IF_ERR_EXIT( 6150 READ_CDPORT_XGXS0_LN0_STATUS_REGr(unit, port, &rval)); 6151 *link = soc_reg_field_get(unit, CDPORT_XGXS0_LN0_STATUS_REGr, rval, LINK_STATUSf); 6152 } 6153 /* next need to check 400G AN enabled or not */ 6154 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 6155 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_GET(unit, pm_info, &is_400g_an, port_index)); 6156 if (is_400g_an) { 6157 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_GET(unit, pm_info, &an_400g_state)); 6158 if (an_400g_state != PM8X50_PORT_AN_COMPLETE) { 6159 *link = 0; 6160 } else { 6161 /* need to check link status, if down, need to restart 400G AN */ 6162 if (*link == 0) { 6163 pm8x50_port_400g_an_state_t an_state = PM8X50_PORT_AN_DISABLE; 6164 uint32 an_wait_link_count = 0; 6165 /* update the 400G An state */ 6166 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_STATE_SET(unit, pm_info, an_state)); 6167 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_WAIT_LINK_COUNT_SET(unit, pm_info, an_wait_link_count)); 6168 _SOC_IF_ERR_EXIT(portmod_port_periodic_callback_register(unit, port, pm8x50_periodic_callback, PORTMOD_THREAD_INTERVAL_1s)); 6169 } 6170 } 6171 } 6172 } else { 6173 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6174 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6175 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6176 6177 _SOC_IF_ERR_EXIT(phymod_phy_link_status_get(&phy_access, 6178 (uint32_t *) link)); 6179 } 6180 } 6181 exit: 6182 SOC_FUNC_RETURN; 6183 } 6184 6185 /*get latch down link status (whether link was ever down since last clear)*/ 6186 int pm8x50_port_link_latch_down_get(int unit, int port, 6187 pm_info_t pm_info, 6188 uint32 flags, int* link) 6189 { 6190 int first_index; 6191 uint32 rval, bitmap; 6192 soc_field_t status_field; 6193 SOC_INIT_FUNC_DEFS; 6194 6195 *link = 0; 6196 6197 _SOC_IF_ERR_EXIT( 6198 _pm8x50_port_index_get(unit, port, pm_info, &first_index, &bitmap)); 6199 6200 switch(first_index) { 6201 case 0: 6202 status_field = PORT0_LINKSTATUSf; 6203 break; 6204 6205 case 1: 6206 status_field = PORT1_LINKSTATUSf; 6207 break; 6208 6209 case 2: 6210 status_field = PORT2_LINKSTATUSf; 6211 break; 6212 6213 case 3: 6214 status_field = PORT3_LINKSTATUSf; 6215 break; 6216 6217 case 4: 6218 status_field = PORT4_LINKSTATUSf; 6219 break; 6220 6221 case 5: 6222 status_field = PORT5_LINKSTATUSf; 6223 break; 6224 6225 case 6: 6226 status_field = PORT6_LINKSTATUSf; 6227 break; 6228 6229 case 7: 6230 status_field = PORT7_LINKSTATUSf; 6231 break; 6232 6233 default: 6234 _SOC_EXIT_WITH_ERR(SOC_E_INTERNAL, 6235 (_SOC_MSG("Port %d, failed to get port index"), port)); 6236 } 6237 6238 _SOC_IF_ERR_EXIT(READ_CDPORT_LINKSTATUS_DOWNr(unit, port, &rval)); 6239 6240 (*link) = soc_reg_field_get(unit, CDPORT_LINKSTATUS_DOWNr, 6241 rval, status_field); 6242 6243 if (PORTMOD_PORT_LINK_LATCH_DOWN_F_CLEAR & flags) { 6244 /* CDPORT_LINKSTATUS_DOWN is sticky register. 6245 * Need to write 1b'1 to clear each field. 6246 */ 6247 rval = 0; 6248 6249 soc_reg_field_set(unit, CDPORT_LINKSTATUS_DOWNr, 6250 &rval, status_field, 1); 6251 6252 _SOC_IF_ERR_EXIT( 6253 WRITE_CDPORT_LINKSTATUS_DOWNr(unit, port, rval)); 6254 } 6255 6256 exit: 6257 SOC_FUNC_RETURN; 6258 } 6259 /* link up event */ 6260 /* 1. AN ports: Update port mode based on reslved speed mode. 6261 * Program resolved Pause settings. 6262 * 2. 1588 ports: timesync adjust. 6263 */ 6264 int pm8x50_port_phy_link_up_event(int unit, int port, pm_info_t pm_info) 6265 { 6266 portmod_access_get_params_t params; 6267 phymod_phy_access_t phy_access; 6268 phymod_autoneg_status_t an_status; 6269 int nof_phys, port_index = -1; 6270 int mac_stage_id, phy_acc; 6271 uint32 reg_val; 6272 uint32 timesync_enable, bitmap, flags = 0; 6273 int num_advert, num_remote, is_400g_an; 6274 portmod_port_speed_ability_t advert_ability[PM8x50_MAX_AN_ABILITY]; 6275 portmod_port_speed_ability_t remote_ability[PM8x50_MAX_AN_ABILITY]; 6276 portmod_pause_control_t pause_ctrl; 6277 portmod_port_phy_pause_t pause_local, pause_remote; 6278 uint8 rx_pause, tx_pause; 6279 6280 SOC_INIT_FUNC_DEFS; 6281 6282 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6283 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6284 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6285 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 6286 6287 /* 1. Update for AN ports */ 6288 _SOC_IF_ERR_EXIT(pm8x50_port_autoneg_status_get(unit, port, pm_info, &an_status)); 6289 if ((an_status.enabled && an_status.locked)) { 6290 /* read the 400G an enabled */ 6291 _SOC_IF_ERR_EXIT(PM8x50_400G_AN_ENABLE_GET(unit, pm_info, &is_400g_an, port_index)); 6292 /*! 6293 * 1.1 Update port mode. 6294 * For PM8x50 autoneg, once the port resolves and link up, 6295 * cdmac_port_mode needs to be updated based on the PCS final port mode. 6296 */ 6297 if (!is_400g_an) { 6298 mac_stage_id = port_index / CDMAC_NUM_LANES; 6299 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 6300 6301 _SOC_IF_ERR_EXIT(READ_CDPORT_MODE_REGr(unit, phy_acc, ®_val)); 6302 6303 if (mac_stage_id) { 6304 /* MAC1 is single-port mode */ 6305 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC1_PORT_MODEf, an_status.resolved_port_mode); 6306 } else { 6307 /* MAC0 is single-port mode */ 6308 soc_reg_field_set(unit, CDPORT_MODE_REGr, ®_val, MAC0_PORT_MODEf, an_status.resolved_port_mode); 6309 } 6310 _SOC_IF_ERR_EXIT(WRITE_CDPORT_MODE_REGr(unit, phy_acc, reg_val)); 6311 } 6312 6313 /*! 6314 * 1.2 Update pause settings. 6315 * Please see $SDK/doc/pause-resolution.txt for more information. 6316 */ 6317 _SOC_IF_ERR_EXIT 6318 (pm8x50_port_autoneg_ability_advert_get(unit, port, pm_info, 6319 PM8x50_MAX_AN_ABILITY, 6320 advert_ability, &num_advert)); 6321 _SOC_IF_ERR_EXIT 6322 (pm8x50_port_autoneg_ability_remote_get(unit, port, pm_info, 6323 PM8x50_MAX_AN_ABILITY, 6324 remote_ability, &num_remote)); 6325 6326 if (num_advert && num_remote) { 6327 pause_local = advert_ability[0].pause; 6328 pause_remote = remote_ability[0].pause; 6329 if ( 6330 ((pause_local == PORTMOD_PORT_PHY_PAUSE_RX) && 6331 (pause_remote == PORTMOD_PORT_PHY_PAUSE_TX)) || 6332 ((pause_local == PORTMOD_PORT_PHY_PAUSE_RX || 6333 pause_local == PORTMOD_PORT_PHY_PAUSE_SYMM) && 6334 (pause_remote == PORTMOD_PORT_PHY_PAUSE_RX || 6335 pause_remote == PORTMOD_PORT_PHY_PAUSE_SYMM)) 6336 ) { 6337 rx_pause = 1; 6338 } else { 6339 rx_pause = 0; 6340 } 6341 if ( 6342 ((pause_local == PORTMOD_PORT_PHY_PAUSE_RX || 6343 pause_local == PORTMOD_PORT_PHY_PAUSE_SYMM) && 6344 (pause_remote == PORTMOD_PORT_PHY_PAUSE_RX || 6345 pause_remote == PORTMOD_PORT_PHY_PAUSE_SYMM)) || 6346 ((pause_local == PORTMOD_PORT_PHY_PAUSE_TX) && 6347 (pause_remote == PORTMOD_PORT_PHY_PAUSE_RX)) 6348 ) { 6349 tx_pause = 1; 6350 } else { 6351 tx_pause = 0; 6352 } 6353 } else { 6354 tx_pause = 0; 6355 rx_pause = 0; 6356 } 6357 6358 _SOC_IF_ERR_EXIT 6359 (pm8x50_port_pause_control_get(unit, port, pm_info, &pause_ctrl)); 6360 if ((pause_ctrl.rx_enable != rx_pause) || 6361 (pause_ctrl.tx_enable != tx_pause)) { 6362 pause_ctrl.rx_enable = rx_pause; 6363 pause_ctrl.tx_enable = tx_pause; 6364 _SOC_IF_ERR_EXIT 6365 (pm8x50_port_pause_control_set(unit, port, pm_info, &pause_ctrl)); 6366 } 6367 } 6368 6369 6370 /* 2. Adjust timesync settings for 1588 port. */ 6371 _SOC_IF_ERR_EXIT(PM8x50_TIMESYNC_ENABLE_GET(unit, pm_info, ×ync_enable, port_index)); 6372 6373 if (timesync_enable) { 6374 /* If 1588 is enabled on the port, need to adjust timesync during link up event. 6375 * rx_ts_update will be enabled at the end of adjust function. 6376 * Current driver code only support EarliestLane mode. 6377 */ 6378 _SOC_IF_ERR_EXIT(phymod_timesync_adjust_set(&phy_access, phymodTimesyncCompensationModeEarliestLane)); 6379 PHYMOD_TIMESYNC_ENABLE_F_RX_SET(flags); 6380 _SOC_IF_ERR_EXIT(phymod_timesync_enable_set(&phy_access, flags, 1)); 6381 /* Wait for one AM spacing time */ 6382 sal_usleep(500); 6383 } 6384 6385 6386 exit: 6387 SOC_FUNC_RETURN; 6388 } 6389 6390 /* link down event */ 6391 /* 1. 1588 port: Disable rx_ts_update. 6392 */ 6393 int pm8x50_port_phy_link_down_event(int unit, int port, pm_info_t pm_info) 6394 { 6395 portmod_access_get_params_t params; 6396 phymod_phy_access_t phy_access; 6397 int nof_phys, port_index = -1; 6398 uint32 timesync_enable, bitmap, flags = 0; 6399 6400 SOC_INIT_FUNC_DEFS; 6401 6402 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 6403 _SOC_IF_ERR_EXIT(PM8x50_TIMESYNC_ENABLE_GET(unit, pm_info, ×ync_enable, port_index)); 6404 6405 if (timesync_enable) { 6406 /* If link down and 1588 is enabled on the port, 6407 * Need to disable rx_ts_update. 6408 */ 6409 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6410 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6411 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6412 PHYMOD_TIMESYNC_ENABLE_F_RX_SET(flags); 6413 _SOC_IF_ERR_EXIT(phymod_timesync_enable_set(&phy_access, flags, 0)); 6414 } 6415 6416 exit: 6417 SOC_FUNC_RETURN; 6418 } 6419 6420 /*PRBS configuration set/get*/ 6421 int pm8x50_port_prbs_config_set(int unit, int port, pm_info_t pm_info, 6422 portmod_prbs_mode_t mode, int flags, 6423 const phymod_prbs_t* config) 6424 { 6425 portmod_access_get_params_t params; 6426 phymod_phy_access_t phy_access; 6427 int nof_phys; 6428 SOC_INIT_FUNC_DEFS; 6429 6430 /* MAC */ 6431 if(mode == 1) { 6432 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 6433 (_SOC_MSG("MAC PRBS is not supported"))); 6434 } 6435 6436 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6437 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6438 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6439 _SOC_IF_ERR_EXIT(phymod_phy_prbs_config_set(&phy_access, flags, config)); 6440 6441 exit: 6442 SOC_FUNC_RETURN; 6443 } 6444 6445 int pm8x50_port_prbs_config_get(int unit, int port, pm_info_t pm_info, 6446 portmod_prbs_mode_t mode, int flags, 6447 phymod_prbs_t* config) 6448 { 6449 portmod_access_get_params_t params; 6450 phymod_phy_access_t phy_access; 6451 int nof_phys; 6452 SOC_INIT_FUNC_DEFS; 6453 6454 /* MAC */ 6455 if(mode == 1) { 6456 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 6457 (_SOC_MSG("MAC PRBS is not supported"))); 6458 } 6459 6460 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6461 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6462 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6463 _SOC_IF_ERR_EXIT(phymod_phy_prbs_config_get(&phy_access, flags, config)); 6464 6465 exit: 6466 SOC_FUNC_RETURN; 6467 } 6468 6469 /*PRBS enable set/get*/ 6470 int pm8x50_port_prbs_enable_set(int unit, int port, pm_info_t pm_info, 6471 portmod_prbs_mode_t mode, int flags, 6472 int enable) 6473 { 6474 portmod_access_get_params_t params; 6475 phymod_phy_access_t phy_access; 6476 int nof_phys; 6477 SOC_INIT_FUNC_DEFS; 6478 6479 /* MAC */ 6480 if(mode == 1) { 6481 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 6482 (_SOC_MSG("MAC PRBS is not supported"))); 6483 } 6484 6485 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6486 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6487 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6488 _SOC_IF_ERR_EXIT(phymod_phy_prbs_enable_set(&phy_access, flags, enable)); 6489 6490 exit: 6491 SOC_FUNC_RETURN; 6492 } 6493 6494 int pm8x50_port_prbs_enable_get(int unit, int port, pm_info_t pm_info, 6495 portmod_prbs_mode_t mode, int flags, 6496 int* enable) 6497 { 6498 portmod_access_get_params_t params; 6499 phymod_phy_access_t phy_access; 6500 int nof_phys; 6501 SOC_INIT_FUNC_DEFS; 6502 6503 /* MAC */ 6504 if(mode == 1) { 6505 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 6506 (_SOC_MSG("MAC PRBS is not supported"))); 6507 } 6508 6509 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6510 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6511 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6512 _SOC_IF_ERR_EXIT(phymod_phy_prbs_enable_get(&phy_access, flags, 6513 (uint32_t *) enable)); 6514 6515 exit: 6516 SOC_FUNC_RETURN; 6517 } 6518 6519 /*PRBS status get*/ 6520 int pm8x50_port_prbs_status_get(int unit, int port, pm_info_t pm_info, 6521 portmod_prbs_mode_t mode, int flags, 6522 phymod_prbs_status_t* status) 6523 { 6524 portmod_access_get_params_t params; 6525 phymod_phy_access_t phy_access; 6526 int nof_phys; 6527 SOC_INIT_FUNC_DEFS; 6528 6529 /* MAC */ 6530 if(mode == 1) { 6531 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 6532 (_SOC_MSG("MAC PRBS is not supported"))); 6533 } 6534 6535 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6536 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6537 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6538 _SOC_IF_ERR_EXIT(phymod_phy_prbs_status_get(&phy_access, flags, status)); 6539 6540 exit: 6541 SOC_FUNC_RETURN; 6542 } 6543 6544 /*Port tx taps set\get*/ 6545 int pm8x50_port_tx_set(int unit, int port, pm_info_t pm_info, const phymod_tx_t* tx) 6546 { 6547 portmod_access_get_params_t params; 6548 phymod_phy_access_t phy_access; 6549 int nof_phys; 6550 SOC_INIT_FUNC_DEFS; 6551 6552 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6553 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6554 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6555 _SOC_IF_ERR_EXIT(phymod_phy_tx_set(&phy_access, tx)); 6556 6557 exit: 6558 SOC_FUNC_RETURN; 6559 } 6560 6561 int pm8x50_port_tx_get(int unit, int port, pm_info_t pm_info, phymod_tx_t* tx) 6562 { 6563 portmod_access_get_params_t params; 6564 phymod_phy_access_t phy_access; 6565 int nof_phys; 6566 SOC_INIT_FUNC_DEFS; 6567 6568 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 6569 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 6570 ¶ms, 1, &phy_access, &nof_phys, NULL)); 6571 _SOC_IF_ERR_EXIT(phymod_phy_tx_get(&phy_access, tx)); 6572 6573 exit: 6574 SOC_FUNC_RETURN; 6575 } 6576 6577 /*Number of lanes get*/ 6578 int pm8x50_port_nof_lanes_get(int unit, int port, pm_info_t pm_info, 6579 int* nof_lanes) 6580 { 6581 int port_index; 6582 uint32_t bitmap, bcnt = 0; 6583 6584 SOC_INIT_FUNC_DEFS; 6585 6586 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get (unit, port, pm_info, &port_index, &bitmap)); 6587 6588 while (bitmap) { 6589 if (bitmap & 0x1) bcnt++; 6590 bitmap >>= 1; 6591 } 6592 *nof_lanes = bcnt; 6593 6594 exit: 6595 SOC_FUNC_RETURN; 6596 } 6597 6598 /*Set port PHYs' firmware mode*/ 6599 int pm8x50_port_firmware_mode_set(int unit, int port, pm_info_t pm_info, 6600 phymod_firmware_mode_t fw_mode) 6601 { 6602 6603 return (SOC_E_NONE); 6604 } 6605 int pm8x50_port_firmware_mode_get(int unit, int port, pm_info_t pm_info, 6606 phymod_firmware_mode_t* fw_mode) 6607 { 6608 6609 return (SOC_E_NONE); 6610 } 6611 6612 /*Filter packets smaller than the specified threshold*/ 6613 int pm8x50_port_runt_threshold_set(int unit, int port, 6614 pm_info_t pm_info, 6615 int value) 6616 { 6617 SOC_INIT_FUNC_DEFS; 6618 _SOC_IF_ERR_EXIT(cdmac_runt_threshold_set(unit, port, value)); 6619 exit: 6620 SOC_FUNC_RETURN; 6621 } 6622 6623 int pm8x50_port_runt_threshold_get(int unit, int port, pm_info_t pm_info, 6624 int* value) 6625 { 6626 SOC_INIT_FUNC_DEFS; 6627 _SOC_IF_ERR_EXIT(cdmac_runt_threshold_get(unit, port, value)); 6628 exit: 6629 SOC_FUNC_RETURN; 6630 } 6631 6632 /*Filter packets bigger than the specified value*/ 6633 int pm8x50_port_max_packet_size_set(int unit, int port, pm_info_t pm_info, 6634 int value) 6635 { 6636 SOC_INIT_FUNC_DEFS; 6637 _SOC_IF_ERR_EXIT(cdmac_rx_max_size_set(unit, port , value)); 6638 exit: 6639 SOC_FUNC_RETURN; 6640 } 6641 int pm8x50_port_max_packet_size_get(int unit, int port, pm_info_t pm_info, 6642 int* value) 6643 { 6644 SOC_INIT_FUNC_DEFS; 6645 _SOC_IF_ERR_EXIT(cdmac_rx_max_size_get(unit, port , value)); 6646 exit: 6647 SOC_FUNC_RETURN; 6648 } 6649 6650 /* 6651 * TX pad packets to the specified size. 6652 * values smaller than 17 means pad is disabled. 6653 */ 6654 int pm8x50_port_pad_size_set(int unit, int port, pm_info_t pm_info, int value) 6655 { 6656 SOC_INIT_FUNC_DEFS; 6657 SOC_NULL_CHECK(pm_info); 6658 6659 _SOC_IF_ERR_EXIT(cdmac_pad_size_set(unit, port , value)); 6660 6661 exit: 6662 SOC_FUNC_RETURN; 6663 } 6664 6665 int pm8x50_port_pad_size_get(int unit, int port, pm_info_t pm_info, int* value) 6666 { 6667 SOC_INIT_FUNC_DEFS; 6668 SOC_NULL_CHECK(pm_info); 6669 6670 _SOC_IF_ERR_EXIT(cdmac_pad_size_get(unit, port , value)); 6671 6672 exit: 6673 SOC_FUNC_RETURN; 6674 } 6675 6676 /*set/get the MAC source address that will be sent in case of Pause/LLFC*/ 6677 int pm8x50_port_tx_mac_sa_set(int unit, int port, pm_info_t pm_info, 6678 sal_mac_addr_t mac_sa) 6679 { 6680 SOC_INIT_FUNC_DEFS; 6681 SOC_NULL_CHECK(pm_info); 6682 6683 _SOC_IF_ERR_EXIT(cdmac_tx_mac_sa_set(unit, port, mac_sa)); 6684 6685 exit: 6686 SOC_FUNC_RETURN; 6687 } 6688 int pm8x50_port_tx_mac_sa_get(int unit, int port, pm_info_t pm_info, 6689 sal_mac_addr_t mac_sa) 6690 { 6691 SOC_INIT_FUNC_DEFS; 6692 SOC_NULL_CHECK(pm_info); 6693 6694 _SOC_IF_ERR_EXIT(cdmac_tx_mac_sa_get(unit, port, mac_sa)); 6695 6696 exit: 6697 SOC_FUNC_RETURN; 6698 } 6699 6700 /* set/get SA recognized for MAC control packets 6701 * in addition to the standard 0x0180C2000001 6702 */ 6703 int pm8x50_port_rx_mac_sa_set(int unit, int port, pm_info_t pm_info, 6704 sal_mac_addr_t mac_sa) 6705 { 6706 SOC_INIT_FUNC_DEFS; 6707 SOC_NULL_CHECK(pm_info); 6708 6709 _SOC_IF_ERR_EXIT(cdmac_rx_mac_sa_set(unit, port, mac_sa)); 6710 6711 exit: 6712 SOC_FUNC_RETURN; 6713 } 6714 int pm8x50_port_rx_mac_sa_get(int unit, int port, pm_info_t pm_info, 6715 sal_mac_addr_t mac_sa) 6716 { 6717 SOC_INIT_FUNC_DEFS; 6718 SOC_NULL_CHECK(pm_info); 6719 6720 _SOC_IF_ERR_EXIT(cdmac_rx_mac_sa_get(unit, port, mac_sa)); 6721 6722 exit: 6723 SOC_FUNC_RETURN; 6724 } 6725 6726 /*set/get Average inter-packet gap*/ 6727 int pm8x50_port_tx_average_ipg_set(int unit, int port, pm_info_t pm_info, 6728 int value) 6729 { 6730 SOC_INIT_FUNC_DEFS; 6731 SOC_NULL_CHECK(pm_info); 6732 6733 _SOC_IF_ERR_EXIT(cdmac_tx_average_ipg_set(unit, port, value)); 6734 6735 exit: 6736 SOC_FUNC_RETURN; 6737 6738 6739 } 6740 int pm8x50_port_tx_average_ipg_get(int unit, int port, pm_info_t pm_info, 6741 int* value) 6742 { 6743 SOC_INIT_FUNC_DEFS; 6744 SOC_NULL_CHECK(pm_info); 6745 6746 _SOC_IF_ERR_EXIT(cdmac_tx_average_ipg_get(unit, port, value)); 6747 6748 exit: 6749 SOC_FUNC_RETURN; 6750 6751 } 6752 6753 /*local fault set/get*/ 6754 int pm8x50_port_local_fault_control_set(int unit, int port, pm_info_t pm_info, 6755 const portmod_local_fault_control_t* control) 6756 { 6757 SOC_INIT_FUNC_DEFS; 6758 SOC_NULL_CHECK(pm_info); 6759 6760 _SOC_IF_ERR_EXIT(cdmac_local_fault_control_set(unit, port, control)); 6761 6762 exit: 6763 SOC_FUNC_RETURN; 6764 } 6765 6766 int pm8x50_port_local_fault_control_get(int unit, int port, pm_info_t pm_info, 6767 portmod_local_fault_control_t* control) 6768 { 6769 SOC_INIT_FUNC_DEFS; 6770 SOC_NULL_CHECK(pm_info); 6771 6772 _SOC_IF_ERR_EXIT(cdmac_local_fault_control_get(unit, port, control)); 6773 6774 exit: 6775 SOC_FUNC_RETURN; 6776 6777 } 6778 6779 /*remote fault set/get*/ 6780 int pm8x50_port_remote_fault_control_set(int unit, int port, pm_info_t pm_info, 6781 const portmod_remote_fault_control_t* control) 6782 { 6783 SOC_INIT_FUNC_DEFS; 6784 SOC_NULL_CHECK(pm_info); 6785 6786 _SOC_IF_ERR_EXIT(cdmac_remote_fault_control_set(unit, port, control)); 6787 6788 exit: 6789 SOC_FUNC_RETURN; 6790 6791 } 6792 int pm8x50_port_remote_fault_control_get(int unit, int port, pm_info_t pm_info, 6793 portmod_remote_fault_control_t* control) 6794 { 6795 SOC_INIT_FUNC_DEFS; 6796 SOC_NULL_CHECK(pm_info); 6797 6798 _SOC_IF_ERR_EXIT(cdmac_remote_fault_control_get(unit, port, control)); 6799 6800 exit: 6801 SOC_FUNC_RETURN; 6802 } 6803 6804 /*local fault steatus get*/ 6805 int pm8x50_port_local_fault_status_get(int unit, int port, pm_info_t pm_info, 6806 int* value) 6807 { 6808 SOC_INIT_FUNC_DEFS; 6809 SOC_NULL_CHECK(pm_info); 6810 6811 _SOC_IF_ERR_EXIT(cdmac_local_fault_status_get(unit, port, value)); 6812 6813 exit: 6814 SOC_FUNC_RETURN; 6815 } 6816 6817 /*remote fault status get*/ 6818 int pm8x50_port_remote_fault_status_get(int unit, int port, pm_info_t pm_info, 6819 int* value) 6820 { 6821 SOC_INIT_FUNC_DEFS; 6822 SOC_NULL_CHECK(pm_info); 6823 6824 _SOC_IF_ERR_EXIT(cdmac_remote_fault_status_get(unit, port, value)); 6825 6826 exit: 6827 SOC_FUNC_RETURN; 6828 } 6829 6830 /*local fault steatus clear*/ 6831 int pm8x50_port_local_fault_status_clear(int unit, int port, pm_info_t pm_info) 6832 { 6833 6834 return (SOC_E_NONE); 6835 } 6836 6837 /*remote fault status clear*/ 6838 int pm8x50_port_remote_fault_status_clear(int unit, int port, 6839 pm_info_t pm_info) 6840 { 6841 6842 return (SOC_E_NONE); 6843 } 6844 6845 int pm8x50_port_pause_control_set(int unit, int port, pm_info_t pm_info, 6846 const portmod_pause_control_t* control) 6847 { 6848 SOC_INIT_FUNC_DEFS; 6849 _SOC_IF_ERR_EXIT(cdmac_pause_control_set(unit, port, control)); 6850 exit: 6851 SOC_FUNC_RETURN; 6852 } 6853 6854 int pm8x50_port_pause_control_get(int unit, int port, pm_info_t pm_info, 6855 portmod_pause_control_t* control) 6856 { 6857 SOC_INIT_FUNC_DEFS; 6858 _SOC_IF_ERR_EXIT(cdmac_pause_control_get(unit, port, control)); 6859 exit: 6860 SOC_FUNC_RETURN; 6861 } 6862 6863 int pm8x50_port_pfc_control_set(int unit, int port, pm_info_t pm_info, 6864 const portmod_pfc_control_t* control) 6865 { 6866 SOC_INIT_FUNC_DEFS; 6867 _SOC_IF_ERR_EXIT(cdmac_pfc_control_set(unit, port, control)); 6868 exit: 6869 SOC_FUNC_RETURN; 6870 } 6871 6872 int pm8x50_port_pfc_control_get(int unit, int port, pm_info_t pm_info, 6873 portmod_pfc_control_t* control) 6874 { 6875 SOC_INIT_FUNC_DEFS; 6876 _SOC_IF_ERR_EXIT(cdmac_pfc_control_get(unit, port, control)); 6877 exit: 6878 SOC_FUNC_RETURN; 6879 } 6880 6881 /*Routine for MAC\PHY sync.*/ 6882 int pm8x50_port_update(int unit, int port, pm_info_t pm_info, 6883 const portmod_port_update_control_t* update_control) 6884 { 6885 6886 return (SOC_E_NONE); 6887 } 6888 6889 /*get port cores' phymod access*/ 6890 int pm8x50_port_core_access_get(int unit, int port, pm_info_t pm_info, 6891 int phyn, int max_cores, 6892 phymod_core_access_t* core_access_arr, 6893 int* nof_cores, int* is_most_ext) 6894 { 6895 SOC_INIT_FUNC_DEFS; 6896 6897 /* There are only internal phys(1) on PM8x50, setting phyn to 0 */ 6898 if(phyn < 0) 6899 { 6900 phyn = 0; 6901 } 6902 6903 _SOC_IF_ERR_EXIT(phymod_core_access_t_init(&core_access_arr[0])); 6904 6905 if( phyn == 0 ){ 6906 sal_memcpy(&core_access_arr[0], 6907 &(PM_8x50_INFO(pm_info)->int_core_access), 6908 sizeof(phymod_core_access_t)); 6909 *nof_cores = 1; 6910 } 6911 6912 if (is_most_ext) { 6913 *is_most_ext = 1; 6914 } 6915 6916 exit: 6917 SOC_FUNC_RETURN; 6918 } 6919 6920 /*Get lane phymod access structure. can be used for per lane operations*/ 6921 int pm8x50_port_phy_lane_access_get(int unit, int port, pm_info_t pm_info, 6922 const portmod_access_get_params_t* params, 6923 int max_phys, 6924 phymod_phy_access_t* phy_access, 6925 int* nof_phys, int* is_most_ext) 6926 { 6927 int rv; 6928 uint32 iphy_lane_mask = 0; 6929 int port_index=0; 6930 int i; 6931 uint32 is_bypassed = 0; 6932 int lane_count; 6933 6934 SOC_INIT_FUNC_DEFS; 6935 6936 if(max_phys > MAX_NUM_CORES) 6937 { 6938 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 6939 (_SOC_MSG("max_phys parameter exceeded the " 6940 "MAX value. max_phys=%d, max allowed %d."), 6941 max_phys, MAX_NUM_CORES)); 6942 } 6943 6944 /* get port index and lane mask */ 6945 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, 6946 &iphy_lane_mask)); 6947 6948 rv = PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &is_bypassed, port_index); 6949 _SOC_IF_ERR_EXIT(rv); 6950 6951 6952 for( i = 0 ; i < max_phys; i++) { 6953 _SOC_IF_ERR_EXIT(phymod_phy_access_t_init(&phy_access[i])); 6954 } 6955 6956 *nof_phys = 1; 6957 /* internal core */ 6958 sal_memcpy (&phy_access[0], &(PM_8x50_INFO(pm_info)->int_core_access), 6959 sizeof(phymod_phy_access_t)); 6960 phy_access[0].access.lane_mask = iphy_lane_mask; 6961 if (params->lane != -1) { 6962 lane_count = 0; 6963 phy_access[0].access.lane_mask = 0; 6964 for (i = 0; i < MAX_PORTS_PER_PM8X50; ++i) 6965 { 6966 if (iphy_lane_mask & (1 << i)) 6967 { 6968 if (lane_count == params->lane) 6969 { 6970 phy_access[0].access.lane_mask = (1 << i); 6971 break; 6972 } 6973 6974 ++lane_count; 6975 } 6976 } 6977 if (phy_access[0].access.lane_mask == 0) { 6978 *nof_phys = 0; 6979 } 6980 } 6981 /* only line is availabe for internal. */ 6982 phy_access[0].port_loc = phymodPortLocLine; 6983 6984 if (is_bypassed) { 6985 PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_SET(phy_access[0].device_op_mode); 6986 } 6987 6988 if (is_most_ext) { 6989 *is_most_ext = 1; 6990 } 6991 6992 exit: 6993 SOC_FUNC_RETURN; 6994 } 6995 /* 6996 * Get lane phymod access structure via pm id. 6997 * This function can be used for getting phy access 6998 * when port is not attached. 6999 * 7000 * If a single lane access is required, please specify the params.lane. 7001 * Otherwise, set params.lane = -1, meaning get lane access for all the 7002 * lanes in the given PM. 7003 */ 7004 int pm8x50_pm_phy_lane_access_get( 7005 int unit, int pm_id, pm_info_t pm_info, 7006 const portmod_access_get_params_t* params, 7007 int max_phys, phymod_phy_access_t* phy_access, 7008 int* nof_phys, int* is_most_ext) 7009 { 7010 uint32 iphy_lane_mask = 0; 7011 int port_index=0; 7012 int i; 7013 int port = -1; 7014 uint32 is_bypassed = 0; 7015 7016 SOC_INIT_FUNC_DEFS; 7017 7018 for( i = 0 ; i < max_phys; i++) { 7019 _SOC_IF_ERR_EXIT(phymod_phy_access_t_init(&phy_access[i])); 7020 } 7021 7022 *nof_phys = 1; 7023 7024 /* internal core */ 7025 sal_memcpy (&phy_access[0], &(PM_8x50_INFO(pm_info)->int_core_access), 7026 sizeof(phymod_phy_access_t)); 7027 7028 if (params->lane != -1) { 7029 /* 7030 * If lane index is not -1, need to check if there is any port attched on 7031 * the given lane. If there is active port on the lane, need to check if 7032 * the lane is working at bypass mode. 7033 */ 7034 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info, params->lane, &port)); 7035 if (port > 0) { 7036 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, 7037 &iphy_lane_mask)); 7038 _SOC_IF_ERR_EXIT(PM8x50_PORT_IS_PCS_BYPASSED_GET(unit, pm_info, &is_bypassed, port_index)); 7039 if (is_bypassed) { 7040 PHYMOD_DEVICE_OP_MODE_PCS_BYPASS_SET(phy_access[0].device_op_mode); 7041 } 7042 } 7043 phy_access[0].access.lane_mask = (0x1 << (params->lane)); 7044 } else { 7045 /* 7046 * If lane index is -1, assume all the lanes are accessed 7047 */ 7048 phy_access[0].access.lane_mask = (0x1 << MAX_PORTS_PER_PM8X50) - 1; 7049 } 7050 /* only line is availabe for internal. */ 7051 phy_access[0].port_loc = phymodPortLocLine; 7052 7053 if (is_most_ext) { 7054 *is_most_ext = 1; 7055 } 7056 exit: 7057 SOC_FUNC_RETURN; 7058 } 7059 7060 /*Port duplex set\get*/ 7061 int pm8x50_port_duplex_set(int unit, int port, pm_info_t pm_info, int enable) 7062 { 7063 SOC_INIT_FUNC_DEFS; 7064 7065 _SOC_IF_ERR_EXIT(cdmac_duplex_set(unit, port, enable)); 7066 exit: 7067 SOC_FUNC_RETURN 7068 } 7069 7070 int pm8x50_port_duplex_get(int unit, int port, pm_info_t pm_info, int* enable) 7071 { 7072 SOC_INIT_FUNC_DEFS; 7073 7074 _SOC_IF_ERR_EXIT(cdmac_duplex_get(unit, port, enable)); 7075 exit: 7076 SOC_FUNC_RETURN 7077 } 7078 7079 /*Port PHY Control register read*/ 7080 int pm8x50_port_phy_reg_read(int unit, int port, pm_info_t pm_info, int lane, 7081 int flags, int reg_addr, uint32* value) 7082 { 7083 portmod_access_get_params_t params; 7084 phymod_phy_access_t phy_access; 7085 int nof_phys; 7086 7087 SOC_INIT_FUNC_DEFS; 7088 7089 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 7090 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 7091 ¶ms, 1, &phy_access, &nof_phys, NULL)); 7092 7093 PM8X50_PHY_REG_SET(reg_addr); 7094 7095 if (lane >= 0) { 7096 reg_addr |= PHYMOD_REG_ACC_AER_IBLK_FORCE_LANE; 7097 reg_addr &= ~(0x7 << PHYMOD_REG_ACCESS_FLAGS_SHIFT); 7098 reg_addr |= ((lane & 0x7) << PHYMOD_REG_ACCESS_FLAGS_SHIFT); 7099 } 7100 _SOC_IF_ERR_EXIT(phymod_phy_reg_read(&phy_access, reg_addr, value)); 7101 7102 7103 exit: 7104 SOC_FUNC_RETURN; 7105 } 7106 7107 /*Port PHY Control register write*/ 7108 int pm8x50_port_phy_reg_write(int unit, int port, pm_info_t pm_info, 7109 int lane, int flags, int reg_addr, uint32 value) 7110 { 7111 portmod_access_get_params_t params; 7112 phymod_phy_access_t phy_access; 7113 int nof_phys; 7114 7115 SOC_INIT_FUNC_DEFS; 7116 7117 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 7118 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 7119 ¶ms, 1, &phy_access, &nof_phys, NULL)); 7120 7121 PM8X50_PHY_REG_SET(reg_addr); 7122 7123 if (lane >= 0) { 7124 reg_addr |= PHYMOD_REG_ACC_AER_IBLK_FORCE_LANE; 7125 reg_addr &= ~(0x7 << PHYMOD_REG_ACCESS_FLAGS_SHIFT); 7126 reg_addr |= ((lane & 0x7) << PHYMOD_REG_ACCESS_FLAGS_SHIFT); 7127 } 7128 _SOC_IF_ERR_EXIT(phymod_phy_reg_write(&phy_access, reg_addr, value)); 7129 7130 exit: 7131 SOC_FUNC_RETURN; 7132 } 7133 7134 /*Port Reset set\get*/ 7135 int pm8x50_port_reset_set(int unit, int port, 7136 pm_info_t pm_info, int mode, 7137 int opcode, int value) 7138 { 7139 SOC_INIT_FUNC_DEFS; 7140 7141 _SOC_IF_ERR_EXIT(portmod_phy_port_reset_set(unit, port, pm_info, 7142 mode, opcode, value)); 7143 exit: 7144 SOC_FUNC_RETURN 7145 } 7146 int pm8x50_port_reset_get(int unit, int port, 7147 pm_info_t pm_info, int mode, 7148 int opcode, int* value) 7149 { 7150 SOC_INIT_FUNC_DEFS; 7151 7152 _SOC_IF_ERR_EXIT(portmod_phy_port_reset_get(unit, port, pm_info, 7153 mode, opcode, value)); 7154 exit: 7155 SOC_FUNC_RETURN 7156 } 7157 7158 /*Drv Name Get*/ 7159 int pm8x50_port_drv_name_get(int unit, int port, 7160 pm_info_t pm_info, 7161 char* name, int len) 7162 { 7163 strncpy(name, "PM8X50 Driver", len); 7164 return (SOC_E_NONE); 7165 } 7166 7167 /*set/get port fec enable according to local/remote FEC ability*/ 7168 int pm8x50_port_fec_enable_set(int unit, int port, pm_info_t pm_info, 7169 uint32 phy_flags, uint32_t enable) 7170 { 7171 portmod_access_get_params_t params; 7172 phymod_phy_access_t phy_access; 7173 int nof_phys; 7174 7175 SOC_INIT_FUNC_DEFS; 7176 7177 if (phy_flags != PORTMOD_INIT_F_INTERNAL_SERDES_ONLY) { 7178 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 7179 (_SOC_MSG("Only internal phys"))); 7180 } 7181 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 7182 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 7183 ¶ms, 1, &phy_access, &nof_phys, NULL)); 7184 _SOC_IF_ERR_EXIT(phymod_phy_fec_enable_set(&phy_access, enable)); 7185 7186 exit: 7187 SOC_FUNC_RETURN; 7188 } 7189 int pm8x50_port_fec_enable_get(int unit, int port, pm_info_t pm_info, 7190 uint32 phy_flags, uint32_t* enable) 7191 { 7192 portmod_access_get_params_t params; 7193 phymod_phy_access_t phy_access; 7194 int nof_phys; 7195 7196 SOC_INIT_FUNC_DEFS; 7197 7198 if (phy_flags != PORTMOD_INIT_F_INTERNAL_SERDES_ONLY) { 7199 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, 7200 (_SOC_MSG("Only internal phys"))); 7201 } 7202 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 7203 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 7204 ¶ms, 1, &phy_access, &nof_phys, NULL)); 7205 _SOC_IF_ERR_EXIT(phymod_phy_fec_enable_get(&phy_access, enable)); 7206 7207 exit: 7208 SOC_FUNC_RETURN; 7209 } 7210 7211 /*get port auto negotiation local ability*/ 7212 int pm8x50_port_ability_advert_set(int unit, int port, pm_info_t pm_info, 7213 uint32 phy_flags, 7214 portmod_port_ability_t* ability) 7215 { 7216 7217 return (SOC_E_NONE); 7218 } 7219 int pm8x50_port_ability_advert_get(int unit, int port, pm_info_t pm_info, 7220 uint32 phy_flags, 7221 portmod_port_ability_t* ability) 7222 { 7223 7224 return (SOC_E_NONE); 7225 } 7226 7227 /*Port ability remote Adv get*/ 7228 int pm8x50_port_ability_remote_get(int unit, int port, pm_info_t pm_info, 7229 uint32 phy_flags, 7230 portmod_port_ability_t* ability) 7231 { 7232 7233 return (SOC_E_NONE); 7234 } 7235 7236 /*Port Mac Control Spacing Stretch*/ 7237 int pm8x50_port_frame_spacing_stretch_set(int unit, int port, 7238 pm_info_t pm_info, int spacing) 7239 { 7240 7241 return (SOC_E_NONE); 7242 } 7243 int pm8x50_port_frame_spacing_stretch_get(int unit, int port, 7244 pm_info_t pm_info, 7245 const int* spacing) 7246 { 7247 7248 return (SOC_E_NONE); 7249 } 7250 7251 /*get port timestamps in fifo*/ 7252 int pm8x50_port_diag_fifo_status_get(int unit, int port, pm_info_t pm_info, 7253 const portmod_fifo_status_t* diag_info) 7254 { 7255 7256 return (SOC_E_NONE); 7257 } 7258 7259 /*set/get pass control frames.*/ 7260 int pm8x50_port_rx_control_set(int unit, int port, pm_info_t pm_info, 7261 const portmod_rx_control_t* rx_ctrl) 7262 { 7263 SOC_INIT_FUNC_DEFS; 7264 7265 if (rx_ctrl->flags & PORTMOD_MAC_PASS_CONTROL_FRAME) { 7266 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_set(unit, port, 7267 CDMAC_RSV_MASK_CONTROL_FRAME, 7268 rx_ctrl->pass_control_frames)); 7269 _SOC_IF_ERR_EXIT(cdmac_pass_control_frame_set(unit, port, rx_ctrl->pass_control_frames)); 7270 } 7271 7272 if (rx_ctrl->flags & PORTMOD_MAC_PASS_PFC_FRAME) { 7273 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_set(unit, port, 7274 CDMAC_RSV_MASK_PFC_FRAME, 7275 rx_ctrl->pass_pfc_frames)); 7276 _SOC_IF_ERR_EXIT(cdmac_pass_pfc_frame_set(unit, port, rx_ctrl->pass_pfc_frames)); 7277 } 7278 7279 if (rx_ctrl->flags & PORTMOD_MAC_PASS_PAUSE_FRAME) { 7280 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_set(unit, port, 7281 CDMAC_RSV_MASK_PAUSE_FRAME, 7282 rx_ctrl->pass_pause_frames)); 7283 _SOC_IF_ERR_EXIT(cdmac_pass_pause_frame_set(unit, port, rx_ctrl->pass_pause_frames)); 7284 } 7285 7286 exit: 7287 SOC_FUNC_RETURN; 7288 } 7289 7290 int pm8x50_port_rx_control_get(int unit, int port, pm_info_t pm_info, 7291 portmod_rx_control_t* rx_ctrl) 7292 { 7293 int rx_pass_control_frames, rx_pass_pfc_frames, rx_pass_pause_frames; 7294 uint32 rsv_pass_control_frames, rsv_pass_pfc_frames, rsv_pass_pause_frames; 7295 7296 SOC_INIT_FUNC_DEFS; 7297 7298 _SOC_IF_ERR_EXIT(cdmac_pass_control_frame_get(unit, port, &rx_pass_control_frames)); 7299 _SOC_IF_ERR_EXIT(cdmac_pass_pfc_frame_get(unit, port, &rx_pass_pfc_frames)); 7300 _SOC_IF_ERR_EXIT(cdmac_pass_pause_frame_get(unit, port, &rx_pass_pause_frames)); 7301 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_get(unit, port, CDMAC_RSV_MASK_CONTROL_FRAME, 7302 &rsv_pass_control_frames)); 7303 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_get(unit, port, CDMAC_RSV_MASK_PFC_FRAME, 7304 &rsv_pass_pfc_frames)); 7305 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_get(unit, port, CDMAC_RSV_MASK_PAUSE_FRAME, 7306 &rsv_pass_pause_frames)); 7307 7308 rx_ctrl->pass_control_frames = rx_pass_control_frames & rsv_pass_control_frames; 7309 rx_ctrl->pass_pfc_frames = rx_pass_pfc_frames & rsv_pass_pfc_frames; 7310 rx_ctrl->pass_pause_frames = rx_pass_pause_frames & rsv_pass_pause_frames; 7311 exit: 7312 SOC_FUNC_RETURN; 7313 } 7314 7315 /*set PFC config registers.*/ 7316 int pm8x50_port_pfc_config_set(int unit, int port, pm_info_t pm_info, 7317 const portmod_pfc_config_t* pfc_cfg) 7318 { 7319 SOC_INIT_FUNC_DEFS; 7320 7321 if (pfc_cfg->classes != 8) { 7322 return SOC_E_PARAM; 7323 } 7324 _SOC_IF_ERR_EXIT(cdmac_pfc_config_set(unit, port, pfc_cfg)); 7325 /* set the pfc frame control in cdmac rsv */ 7326 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_set(unit, port, 7327 CDMAC_RSV_MASK_PFC_FRAME, 7328 pfc_cfg->rxpass)); 7329 exit: 7330 SOC_FUNC_RETURN; 7331 } 7332 7333 int pm8x50_port_pfc_config_get(int unit, int port, pm_info_t pm_info, 7334 portmod_pfc_config_t* pfc_cfg) 7335 { 7336 SOC_INIT_FUNC_DEFS; 7337 7338 pfc_cfg->classes = 8; 7339 _SOC_IF_ERR_EXIT(cdmac_pfc_config_get(unit, port, pfc_cfg)); 7340 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_control_get(unit, port, 7341 CDMAC_RSV_MASK_PFC_FRAME, 7342 &pfc_cfg->rxpass)); 7343 exit: 7344 SOC_FUNC_RETURN; 7345 } 7346 7347 /*set EEE Config.*/ 7348 int pm8x50_port_eee_set(int unit, int port, pm_info_t pm_info, 7349 const portmod_eee_t* eee) 7350 { 7351 7352 return (SOC_E_UNAVAIL); 7353 } 7354 int pm8x50_port_eee_get(int unit, int port, pm_info_t pm_info, 7355 portmod_eee_t* eee) 7356 { 7357 7358 return (SOC_E_UNAVAIL); 7359 } 7360 7361 /*set EEE Config.*/ 7362 int pm8x50_port_eee_clock_set(int unit, int port, pm_info_t pm_info, 7363 const portmod_eee_clock_t* eee_clk) 7364 { 7365 7366 return (SOC_E_NONE); 7367 } 7368 int pm8x50_port_eee_clock_get(int unit, int port, pm_info_t pm_info, 7369 portmod_eee_clock_t* eee_clk) 7370 { 7371 7372 return (SOC_E_NONE); 7373 } 7374 7375 /*set Vlan Inner/Outer tag.*/ 7376 int pm8x50_port_vlan_tag_set(int unit, int port, pm_info_t pm_info, 7377 const portmod_vlan_tag_t* vlan_tag) 7378 { 7379 SOC_INIT_FUNC_DEFS; 7380 SOC_NULL_CHECK(pm_info); 7381 7382 _SOC_IF_ERR_EXIT(cdmac_rx_vlan_tag_set (unit, port, 7383 vlan_tag->outer_vlan_tag, 7384 vlan_tag->inner_vlan_tag)); 7385 exit: 7386 SOC_FUNC_RETURN; 7387 } 7388 int pm8x50_port_vlan_tag_get(int unit, int port, pm_info_t pm_info, 7389 portmod_vlan_tag_t* vlan_tag) 7390 { 7391 SOC_INIT_FUNC_DEFS; 7392 SOC_NULL_CHECK(pm_info); 7393 7394 _SOC_IF_ERR_EXIT(cdmac_rx_vlan_tag_get (unit, port, 7395 (int*)&vlan_tag->outer_vlan_tag, 7396 (int*)&vlan_tag->inner_vlan_tag)); 7397 exit: 7398 SOC_FUNC_RETURN; 7399 } 7400 7401 /*set modid field.*/ 7402 int pm8x50_port_modid_set(int unit, int port, pm_info_t pm_info, int value) 7403 { 7404 7405 return (SOC_E_NONE); 7406 } 7407 7408 /*set modid field.*/ 7409 int pm8x50_port_led_chain_config(int unit, int port, pm_info_t pm_info, 7410 int value) 7411 { 7412 7413 return (SOC_E_NONE); 7414 } 7415 7416 /*set modid field.*/ 7417 int pm8x50_port_clear_rx_lss_status_set(int unit, int port, pm_info_t pm_info, 7418 int lcl_fault, int rmt_fault) 7419 { 7420 7421 return (SOC_E_NONE); 7422 } 7423 int pm8x50_port_clear_rx_lss_status_get(int unit, int port, pm_info_t pm_info, 7424 int* lcl_fault, int* rmt_fault) 7425 { 7426 7427 return (SOC_E_NONE); 7428 } 7429 7430 /*Attaches an external phy lane to a specific port macro*/ 7431 int pm8x50_xphy_lane_attach_to_pm(int unit, 7432 pm_info_t pm_info, int iphy, int phyn, 7433 const portmod_xphy_lane_connection_t* lane_connection) 7434 { 7435 7436 return (SOC_E_NONE); 7437 } 7438 7439 /*Attaches an external phy lane to a specific port macro*/ 7440 int pm8x50_xphy_lane_detach_from_pm(int unit, 7441 pm_info_t pm_info, int iphy, int phyn, 7442 portmod_xphy_lane_connection_t* lane_connection) 7443 { 7444 7445 return (SOC_E_NONE); 7446 } 7447 7448 int pm8x50_port_mac_link_get(int unit, int port, pm_info_t pm_info, int* link) 7449 { 7450 uint32 reg_val, bitmap; 7451 int port_index, phy_acc; 7452 SOC_INIT_FUNC_DEFS; 7453 SOC_NULL_CHECK(pm_info); 7454 7455 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 7456 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 7457 7458 switch(port_index) { 7459 case 0: 7460 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN0_STATUS_REGr(unit, phy_acc, ®_val)); 7461 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN0_STATUS_REGr, reg_val, LINK_STATUSf); 7462 break; 7463 7464 case 1: 7465 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN1_STATUS_REGr(unit, phy_acc, ®_val)); 7466 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN1_STATUS_REGr, reg_val, LINK_STATUSf); 7467 break; 7468 7469 case 2: 7470 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN2_STATUS_REGr(unit, phy_acc, ®_val)); 7471 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN2_STATUS_REGr, reg_val, LINK_STATUSf); 7472 break; 7473 7474 case 3: 7475 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN3_STATUS_REGr(unit, phy_acc, ®_val)); 7476 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN3_STATUS_REGr, reg_val, LINK_STATUSf); 7477 break; 7478 7479 case 4: 7480 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN4_STATUS_REGr(unit, phy_acc, ®_val)); 7481 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN4_STATUS_REGr, reg_val, LINK_STATUSf); 7482 break; 7483 7484 case 5: 7485 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN5_STATUS_REGr(unit, phy_acc, ®_val)); 7486 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN5_STATUS_REGr, reg_val, LINK_STATUSf); 7487 break; 7488 7489 case 6: 7490 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN6_STATUS_REGr(unit, phy_acc, ®_val)); 7491 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN6_STATUS_REGr, reg_val, LINK_STATUSf); 7492 break; 7493 7494 case 7: 7495 _SOC_IF_ERR_EXIT(READ_CDPORT_XGXS0_LN7_STATUS_REGr(unit, phy_acc, ®_val)); 7496 (*link) = soc_reg_field_get(unit, CDPORT_XGXS0_LN7_STATUS_REGr, reg_val, LINK_STATUSf); 7497 break; 7498 7499 default: 7500 _SOC_EXIT_WITH_ERR(SOC_E_INTERNAL, 7501 (_SOC_MSG("Port %d, failed to get port index"), port)); 7502 } 7503 7504 exit: 7505 SOC_FUNC_RETURN; 7506 } 7507 7508 /*Toggle Lag Failover Status.*/ 7509 int pm8x50_port_lag_failover_status_toggle(int unit, int port, 7510 pm_info_t pm_info) 7511 { 7512 int phy_acc; 7513 uint32_t rval; 7514 int link = 0; 7515 soc_timeout_t to; 7516 7517 SOC_INIT_FUNC_DEFS; 7518 7519 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 7520 7521 /* Link status to IPIPE is updated by H/W and driven based on both the 7522 * rising edge of CDPORT_LAG_FAILOVER_CONFIG.LINK_STATUS_UP and 7523 * actual link up status from Serdes. 7524 * In some loopback scenarios it may take longer time to see Serdes link up status. 7525 */ 7526 soc_timeout_init(&to, 10000, 0); 7527 7528 do { 7529 _SOC_IF_ERR_EXIT(pm8x50_port_mac_link_get(unit, port, pm_info, &link)); 7530 if (link) { 7531 break; 7532 } 7533 } while(!soc_timeout_check(&to)); 7534 7535 /* Toggle link_status_up bit to notify IPIPE on link up */ 7536 _SOC_IF_ERR_EXIT(READ_CDPORT_LAG_FAILOVER_CONFIGr(unit, phy_acc, &rval)); 7537 soc_reg_field_set(unit, CDPORT_LAG_FAILOVER_CONFIGr, &rval, LINK_STATUS_UPf, 1); 7538 _SOC_IF_ERR_EXIT(WRITE_CDPORT_LAG_FAILOVER_CONFIGr(unit, phy_acc, rval)); 7539 soc_reg_field_set(unit, CDPORT_LAG_FAILOVER_CONFIGr, &rval, LINK_STATUS_UPf, 0); 7540 _SOC_IF_ERR_EXIT(WRITE_CDPORT_LAG_FAILOVER_CONFIGr(unit, phy_acc, rval)); 7541 7542 exit: 7543 SOC_FUNC_RETURN; 7544 } 7545 7546 /*Toggle Lag Failover loopback set / get.*/ 7547 int pm8x50_port_lag_failover_loopback_set(int unit, int port, 7548 pm_info_t pm_info, 7549 int value) 7550 { 7551 SOC_INIT_FUNC_DEFS; 7552 SOC_NULL_CHECK(pm_info); 7553 7554 _SOC_IF_ERR_EXIT(cdmac_lag_failover_loopback_set(unit, port, value)); 7555 exit: 7556 SOC_FUNC_RETURN; 7557 } 7558 int pm8x50_port_lag_failover_loopback_get(int unit, int port, 7559 pm_info_t pm_info, 7560 int* value) 7561 { 7562 SOC_INIT_FUNC_DEFS; 7563 SOC_NULL_CHECK(pm_info); 7564 7565 _SOC_IF_ERR_EXIT(cdmac_lag_failover_loopback_get(unit, port, value)); 7566 exit: 7567 SOC_FUNC_RETURN; 7568 } 7569 7570 /*set modid field.*/ 7571 int pm8x50_port_mode_set(int unit, int port, pm_info_t pm_info, 7572 const portmod_port_mode_info_t* mode) 7573 { 7574 7575 return (SOC_E_NONE); 7576 } 7577 7578 STATIC 7579 int _cdport_mode_get(int unit, int port, pm_info_t pm_info, 7580 int first_phy_index, portmod_port_mode_info_t *p_mode) 7581 { 7582 uint32 reg_val = 0, port_mode = 0; 7583 int phy_acc, mac_id = 0, this_phy_index; 7584 7585 SOC_INIT_FUNC_DEFS; 7586 7587 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 7588 7589 _SOC_IF_ERR_EXIT(READ_CDPORT_MODE_REGr(unit, phy_acc, ®_val)); 7590 port_mode = soc_reg_field_get(unit, CDPORT_MODE_REGr, reg_val, SINGLE_PORT_MODE_SPEED_400Gf); 7591 if (port_mode){ 7592 p_mode->cur_mode = portmodPortModeSingle; 7593 p_mode->lanes = 8; 7594 p_mode->port_index = 0; 7595 } else { 7596 mac_id = first_phy_index / CDMAC_NUM_LANES; 7597 this_phy_index = first_phy_index % CDMAC_NUM_LANES; 7598 if (mac_id) { 7599 /* CDMAC_1 Port Mode */ 7600 port_mode = soc_reg_field_get(unit, CDPORT_MODE_REGr, reg_val, MAC1_PORT_MODEf); 7601 } else { 7602 /* CDMAC_0 Port Mode*/ 7603 port_mode = soc_reg_field_get(unit, CDPORT_MODE_REGr, reg_val, MAC0_PORT_MODEf); 7604 } 7605 switch (port_mode) { 7606 case 0: 7607 p_mode->cur_mode = portmodPortModeQuad; 7608 p_mode->lanes = 1; 7609 p_mode->port_index = this_phy_index; 7610 break; 7611 case 1: 7612 p_mode->cur_mode = portmodPortModeTri012; 7613 if ((this_phy_index == 0)||(this_phy_index == 1)) { 7614 p_mode->lanes = 1; 7615 } else { 7616 p_mode->lanes = 2; 7617 } 7618 p_mode->port_index = this_phy_index; 7619 break; 7620 case 2: 7621 p_mode->cur_mode = portmodPortModeTri023; 7622 if ((this_phy_index == 2)||(this_phy_index == 3)) { 7623 p_mode->lanes = 1; 7624 } else { 7625 p_mode->lanes = 2; 7626 } 7627 p_mode->port_index = this_phy_index; 7628 break; 7629 case 3: 7630 p_mode->cur_mode = portmodPortModeDual; 7631 p_mode->lanes = 2; 7632 p_mode->port_index = this_phy_index; 7633 break; 7634 case 4: 7635 p_mode->cur_mode = portmodPortModeSingle; 7636 p_mode->lanes = 4; 7637 p_mode->port_index = this_phy_index; 7638 break; 7639 default: 7640 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Invalid port mode"))); 7641 break; 7642 } 7643 } 7644 7645 exit: 7646 SOC_FUNC_RETURN; 7647 7648 } 7649 7650 int pm8x50_port_mode_get(int unit, int port, pm_info_t pm_info, 7651 portmod_port_mode_info_t* mode) 7652 { 7653 int port_index; 7654 uint32_t bitmap; 7655 7656 SOC_INIT_FUNC_DEFS; 7657 7658 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get (unit, port, pm_info, &port_index, &bitmap)); 7659 _SOC_IF_ERR_EXIT(_cdport_mode_get(unit, port, pm_info, port_index, mode)); 7660 7661 exit: 7662 SOC_FUNC_RETURN; 7663 } 7664 7665 /*set port encap.*/ 7666 int pm8x50_port_encap_set(int unit, int port, pm_info_t pm_info, 7667 int flags, portmod_encap_t encap) 7668 { 7669 SOC_INIT_FUNC_DEFS; 7670 SOC_NULL_CHECK(pm_info); 7671 7672 _SOC_IF_ERR_EXIT(cdmac_encap_set(unit, port, flags, encap)); 7673 exit: 7674 SOC_FUNC_RETURN; 7675 } 7676 int pm8x50_port_encap_get(int unit, int port, pm_info_t pm_info, 7677 int* flags, portmod_encap_t* encap) 7678 { 7679 SOC_INIT_FUNC_DEFS; 7680 SOC_NULL_CHECK(pm_info); 7681 7682 _SOC_IF_ERR_EXIT(cdmac_encap_get(unit, port, flags, encap)); 7683 exit: 7684 SOC_FUNC_RETURN; 7685 } 7686 7687 /*set port register higig field.*/ 7688 int pm8x50_port_higig_mode_set(int unit, int port, 7689 pm_info_t pm_info, 7690 int mode) 7691 { 7692 7693 return (SOC_E_NONE); 7694 } 7695 int pm8x50_port_higig_mode_get(int unit, int port, 7696 pm_info_t pm_info, 7697 int* mode) 7698 { 7699 7700 return (SOC_E_NONE); 7701 } 7702 7703 /*set port register higig field.*/ 7704 int pm8x50_port_higig2_mode_set(int unit, int port, 7705 pm_info_t pm_info, 7706 int mode) 7707 { 7708 7709 return (SOC_E_NONE); 7710 } 7711 int pm8x50_port_higig2_mode_get(int unit, int port, 7712 pm_info_t pm_info, 7713 int* mode) 7714 { 7715 7716 return (SOC_E_NONE); 7717 } 7718 7719 /*set port register port type field.*/ 7720 int pm8x50_port_config_port_type_set(int unit, int port, 7721 pm_info_t pm_info, 7722 int type) 7723 { 7724 7725 return (SOC_E_NONE); 7726 } 7727 int pm8x50_port_config_port_type_get(int unit, int port, 7728 pm_info_t pm_info, 7729 int* type) 7730 { 7731 7732 return (SOC_E_NONE); 7733 } 7734 7735 /*set/get hwfailover for trident.*/ 7736 int pm8x50_port_trunk_hwfailover_config_set(int unit, int port, 7737 pm_info_t pm_info, 7738 int hw_count) 7739 { 7740 int old_failover_en=0, new_failover_en = 0; 7741 int old_link_status_sel=0, new_link_status_sel=0; 7742 int old_reset_flow_control=0, new_reset_flow_control = 0; 7743 int lag_failover_lpbk; 7744 SOC_INIT_FUNC_DEFS; 7745 7746 if (hw_count) { 7747 new_failover_en = 1; 7748 new_link_status_sel = 1; 7749 new_reset_flow_control = 1; 7750 } 7751 7752 _SOC_IF_ERR_EXIT(cdmac_lag_failover_loopback_get(unit, port, 7753 &lag_failover_lpbk)); 7754 7755 if (lag_failover_lpbk) { 7756 return (SOC_E_NONE); 7757 } 7758 7759 _SOC_IF_ERR_EXIT(cdmac_lag_failover_en_get(unit, port, 7760 &old_failover_en)); 7761 _SOC_IF_ERR_EXIT(cdmac_sw_link_status_select_get(unit, port, 7762 &old_link_status_sel)); 7763 7764 if (old_failover_en != new_failover_en || 7765 old_link_status_sel != new_link_status_sel) { 7766 7767 _SOC_IF_ERR_EXIT(cdmac_sw_link_status_select_set(unit, port, 7768 new_link_status_sel)); 7769 _SOC_IF_ERR_EXIT(cdmac_lag_failover_en_set(unit, port, 7770 new_failover_en)); 7771 } 7772 7773 _SOC_IF_ERR_EXIT(cdmac_reset_fc_timers_on_link_dn_get(unit, 7774 port, &old_reset_flow_control)); 7775 if (old_reset_flow_control != new_reset_flow_control) { 7776 _SOC_IF_ERR_EXIT(cdmac_reset_fc_timers_on_link_dn_set(unit, 7777 port, new_reset_flow_control)); 7778 } 7779 7780 exit: 7781 SOC_FUNC_RETURN; 7782 } 7783 int pm8x50_port_trunk_hwfailover_config_get(int unit, int port, 7784 pm_info_t pm_info, 7785 int* enable) 7786 { 7787 SOC_INIT_FUNC_DEFS; 7788 7789 _SOC_IF_ERR_EXIT(cdmac_lag_failover_en_get(unit, port, enable)); 7790 exit: 7791 SOC_FUNC_RETURN; 7792 } 7793 7794 /*set/get hwfailover for trident.*/ 7795 int pm8x50_port_trunk_hwfailover_status_get(int unit, int port, 7796 pm_info_t pm_info, 7797 int* loopback) 7798 { 7799 SOC_INIT_FUNC_DEFS; 7800 7801 _SOC_IF_ERR_EXIT(cdmac_lag_failover_loopback_get(unit, port, 7802 loopback)); 7803 exit: 7804 SOC_FUNC_RETURN; 7805 } 7806 7807 /*set/get hwfailover for trident.*/ 7808 int pm8x50_port_diag_ctrl(int unit, int port, pm_info_t pm_info, 7809 uint32 inst, int op_type, int op_cmd, 7810 const void* arg) 7811 { 7812 phymod_phy_access_t phy_access[1+MAX_PHYN]; 7813 portmod_access_get_params_t params; 7814 int nof_phys = 0; 7815 7816 SOC_INIT_FUNC_DEFS; 7817 /* Only internal phy supported. */ 7818 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 7819 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 7820 ¶ms, 1, phy_access, &nof_phys, NULL)); 7821 7822 _SOC_IF_ERR_EXIT(portmod_phy_port_diag_ctrl(unit, port, phy_access, nof_phys, inst, op_type, op_cmd, arg)); 7823 7824 exit: 7825 SOC_FUNC_RETURN; 7826 7827 } 7828 7829 /*Get/Set InterFrameGap Setting. */ 7830 int pm8x50_port_ifg_set(int unit, int port, pm_info_t pm_info, int speed, 7831 soc_port_duplex_t duplex, int ifg, int* real_ifg) 7832 { 7833 7834 return (SOC_E_NONE); 7835 } 7836 int pm8x50_port_ifg_get(int unit, int port, pm_info_t pm_info, int speed, 7837 soc_port_duplex_t duplex, int* ifg) 7838 { 7839 7840 return (SOC_E_NONE); 7841 } 7842 7843 /*Get the reference clock value 156 or 125.*/ 7844 int pm8x50_port_ref_clk_get(int unit, int port, 7845 pm_info_t pm_info, 7846 int* ref_clk) 7847 { 7848 *ref_clk = pm_info->pm_data.pm8x50_db->ref_clk; 7849 7850 return (SOC_E_NONE); 7851 } 7852 7853 /*Disable lag failover.*/ 7854 int pm8x50_port_lag_failover_disable(int unit, int port, pm_info_t pm_info) 7855 { 7856 SOC_INIT_FUNC_DEFS; 7857 7858 _SOC_IF_ERR_EXIT(cdmac_lag_failover_disable(unit, port)); 7859 7860 exit: 7861 SOC_FUNC_RETURN; 7862 } 7863 7864 /*Disable lag failover.*/ 7865 int pm8x50_port_lag_remove_failover_lpbk_set(int unit, int port, 7866 pm_info_t pm_info, int val) 7867 { 7868 SOC_INIT_FUNC_DEFS; 7869 7870 _SOC_IF_ERR_EXIT(cdmac_lag_remove_failover_lpbk_set(unit, port, val)); 7871 7872 exit: 7873 SOC_FUNC_RETURN; 7874 } 7875 int pm8x50_port_lag_remove_failover_lpbk_get(int unit, int port, 7876 pm_info_t pm_info, int* val) 7877 { 7878 SOC_INIT_FUNC_DEFS; 7879 7880 _SOC_IF_ERR_EXIT(cdmac_lag_remove_failover_lpbk_get(unit, port, val)); 7881 7882 exit: 7883 SOC_FUNC_RETURN; 7884 } 7885 7886 int pm8x50_port_cntmaxsize_set(int unit, int port, pm_info_t pm_info, int val) 7887 { 7888 return (cdmac_cntmaxsize_set(unit, port, val)); 7889 } 7890 7891 int pm8x50_port_cntmaxsize_get(int unit, int port, pm_info_t pm_info, int* val) 7892 { 7893 return (cdmac_cntmaxsize_get(unit, port, val)); 7894 } 7895 7896 /*Get Info needed to restore after drain cells.*/ 7897 int pm8x50_port_drain_cell_get(int unit, int port, pm_info_t pm_info, 7898 portmod_drain_cells_t* drain_cells) 7899 { 7900 SOC_INIT_FUNC_DEFS; 7901 7902 _SOC_IF_ERR_EXIT(cdmac_drain_cell_get(unit, port, drain_cells)); 7903 7904 exit: 7905 SOC_FUNC_RETURN; 7906 } 7907 7908 /*Restore informaation after drain cells.*/ 7909 int pm8x50_port_drain_cell_stop(int unit, int port, pm_info_t pm_info, 7910 const portmod_drain_cells_t* drain_cells) 7911 { 7912 SOC_INIT_FUNC_DEFS; 7913 7914 _SOC_IF_ERR_EXIT(cdmac_drain_cell_stop(unit, port, drain_cells)); 7915 7916 exit: 7917 SOC_FUNC_RETURN; 7918 } 7919 7920 /*Restore informaation after drain cells.*/ 7921 int pm8x50_port_drain_cell_start(int unit, int port, pm_info_t pm_info) 7922 { 7923 SOC_INIT_FUNC_DEFS; 7924 7925 _SOC_IF_ERR_EXIT(cdmac_drain_cell_start(unit, port)); 7926 7927 exit: 7928 SOC_FUNC_RETURN; 7929 } 7930 7931 /**/ 7932 int pm8x50_port_drain_cells_rx_enable(int unit, int port, 7933 pm_info_t pm_info, 7934 int rx_en) 7935 { 7936 SOC_INIT_FUNC_DEFS; 7937 7938 _SOC_IF_ERR_EXIT(cdmac_drain_cells_rx_enable(unit, port, rx_en)); 7939 7940 exit: 7941 SOC_FUNC_RETURN; 7942 } 7943 7944 /**/ 7945 int pm8x50_port_egress_queue_drain_rx_en(int unit, int port, 7946 pm_info_t pm_info, 7947 int rx_en) 7948 { 7949 SOC_INIT_FUNC_DEFS; 7950 7951 _SOC_IF_ERR_EXIT(cdmac_egress_queue_drain_rx_en(unit, port, rx_en)); 7952 7953 exit: 7954 SOC_FUNC_RETURN; 7955 } 7956 7957 /**/ 7958 int pm8x50_port_mac_ctrl_set(int unit, int port, 7959 pm_info_t pm_info, 7960 uint64 ctrl) 7961 { 7962 SOC_INIT_FUNC_DEFS; 7963 7964 _SOC_IF_ERR_EXIT(cdmac_mac_ctrl_set(unit, port, ctrl)); 7965 7966 exit: 7967 SOC_FUNC_RETURN; 7968 } 7969 7970 /**/ 7971 int pm8x50_port_txfifo_cell_cnt_get(int unit, int port, 7972 pm_info_t pm_info, 7973 uint32* cnt) 7974 { 7975 SOC_INIT_FUNC_DEFS; 7976 7977 _SOC_IF_ERR_EXIT(cdmac_txfifo_cell_cnt_get(unit, port, cnt)); 7978 7979 exit: 7980 SOC_FUNC_RETURN; 7981 } 7982 7983 /**/ 7984 int pm8x50_port_egress_queue_drain_get(int unit, int port, 7985 pm_info_t pm_info, 7986 uint64* ctrl, int* rxen) 7987 { 7988 SOC_INIT_FUNC_DEFS; 7989 7990 _SOC_IF_ERR_EXIT(cdmac_egress_queue_drain_get(unit, port, ctrl, rxen)); 7991 7992 exit: 7993 SOC_FUNC_RETURN; 7994 } 7995 7996 /**/ 7997 int pm8x50_port_mac_reset_set(int unit, int port, pm_info_t pm_info, int val) 7998 { 7999 SOC_INIT_FUNC_DEFS; 8000 8001 _SOC_IF_ERR_EXIT(cdmac_soft_reset_set(unit, port, val)); 8002 8003 exit: 8004 SOC_FUNC_RETURN; 8005 } 8006 8007 int pm8x50_port_mac_reset_get(int unit, int port, pm_info_t pm_info, int* val) 8008 { 8009 SOC_INIT_FUNC_DEFS; 8010 8011 _SOC_IF_ERR_EXIT(cdmac_soft_reset_get(unit, port, val)); 8012 8013 exit: 8014 SOC_FUNC_RETURN; 8015 } 8016 8017 /**/ 8018 int pm8x50_port_soft_reset_toggle(int unit, int port, pm_info_t pm_info, int idx) 8019 { 8020 8021 return (SOC_E_NONE); 8022 } 8023 8024 /*Check if MAC needs to be reset.*/ 8025 int pm8x50_port_mac_reset_check(int unit, int port, 8026 pm_info_t pm_info, 8027 int enable, int* reset) 8028 { 8029 return (cdmac_reset_check(unit, port, enable, reset)); 8030 } 8031 8032 /**/ 8033 int pm8x50_port_core_num_get(int unit, int port, 8034 pm_info_t pm_info, 8035 int* core_num) 8036 { 8037 *core_num = PM_8x50_INFO(pm_info)->core_num; 8038 return (SOC_E_NONE); 8039 } 8040 8041 /**/ 8042 int pm8x50_port_e2ecc_hdr_set(int unit, int port, pm_info_t pm_info, 8043 const portmod_port_higig_e2ecc_hdr_t* e2ecc_hdr) 8044 { 8045 8046 return (SOC_E_NONE); 8047 } 8048 int pm8x50_port_e2ecc_hdr_get(int unit, int port, pm_info_t pm_info, 8049 portmod_port_higig_e2ecc_hdr_t* e2ecc_hdr) 8050 { 8051 8052 return (SOC_E_NONE); 8053 } 8054 8055 /**/ 8056 int pm8x50_port_e2e_enable_set(int unit, int port, 8057 pm_info_t pm_info, 8058 int enable) 8059 { 8060 8061 return (SOC_E_NONE); 8062 } 8063 int pm8x50_port_e2e_enable_get(int unit, int port, 8064 pm_info_t pm_info, 8065 int* enable) 8066 { 8067 8068 return (SOC_E_NONE); 8069 } 8070 8071 /*get the speed for the specified port*/ 8072 int pm8x50_port_speed_get(int unit, int port, pm_info_t pm_info, int* speed) 8073 { 8074 phymod_phy_speed_config_t speed_config; 8075 phymod_phy_access_t phy_access; 8076 portmod_access_get_params_t params; 8077 int nof_phys; 8078 8079 SOC_INIT_FUNC_DEFS; 8080 8081 *speed = 0; 8082 8083 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8084 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8085 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8086 8087 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8088 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8089 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_t_init(&speed_config)); 8090 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_get(&phy_access, &speed_config)); 8091 8092 *speed = speed_config.data_rate; 8093 exit: 8094 SOC_FUNC_RETURN; 8095 } 8096 8097 /*TSC refere clock input and output set/get*/ 8098 int pm8x50_port_tsc_refclock_set(int unit, int port, 8099 pm_info_t pm_info, 8100 int ref_in, int ref_out) 8101 { 8102 8103 return (SOC_E_NONE); 8104 } 8105 int pm8x50_port_tsc_refclock_get(int unit, int port, 8106 pm_info_t pm_info, 8107 int* ref_in, int* ref_out) 8108 { 8109 8110 return (SOC_E_NONE); 8111 } 8112 8113 /*Port discard set*/ 8114 int pm8x50_port_discard_set(int unit, int port, pm_info_t pm_info, int discard) 8115 { 8116 SOC_INIT_FUNC_DEFS; 8117 8118 _SOC_IF_ERR_EXIT(cdmac_discard_set(unit, port, discard)); 8119 8120 exit: 8121 SOC_FUNC_RETURN; 8122 } 8123 8124 /*Port soft reset set set*/ 8125 int pm8x50_port_soft_reset_set(int unit, int port, pm_info_t pm_info, 8126 int idx, int val, int flags) 8127 { 8128 8129 return (SOC_E_NONE); 8130 } 8131 8132 /*Port tx_en=0 and softreset mac*/ 8133 int pm8x50_port_tx_down(int unit, int port, pm_info_t pm_info) 8134 { 8135 SOC_INIT_FUNC_DEFS; 8136 8137 _SOC_IF_ERR_EXIT(cdmac_tx_enable_set(unit, port, 0)); 8138 _SOC_IF_ERR_EXIT(cdmac_discard_set(unit, port, 0)); 8139 _SOC_IF_ERR_EXIT(cdmac_soft_reset_set(unit, port, 1)); 8140 8141 exit: 8142 SOC_FUNC_RETURN; 8143 } 8144 8145 /*reconfig pgw.*/ 8146 int pm8x50_port_pgw_reconfig(int unit, int port, pm_info_t pm_info, 8147 const portmod_port_mode_info_t* pmode, 8148 int phy_port, int flags) 8149 { 8150 8151 return (SOC_E_NONE); 8152 } 8153 8154 /*Routine to notify internal phy of external phy link state.*/ 8155 int pm8x50_port_notify(int unit, int port, pm_info_t pm_info, int link) 8156 { 8157 8158 return (SOC_E_NONE); 8159 } 8160 8161 /*port control phy timesync config set/get*/ 8162 int pm8x50_port_control_phy_timesync_set(int unit, 8163 int port, pm_info_t pm_info, 8164 portmod_port_control_phy_timesync_t config, 8165 uint64 value) 8166 { 8167 portmod_access_get_params_t params; 8168 phymod_phy_access_t phy_access; 8169 int nof_phys; 8170 uint32_t flags = 0; 8171 8172 SOC_INIT_FUNC_DEFS; 8173 8174 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8175 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8176 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8177 8178 if (config == SOC_PORT_CONTROL_PHY_TIMESYNC_TIMESTAMP_ADJUST) { 8179 PHYMOD_TIMESYNC_ENABLE_F_RX_SET(flags); 8180 _SOC_IF_ERR_EXIT(phymod_timesync_enable_set(&phy_access, flags, 0)); 8181 8182 } 8183 _SOC_IF_ERR_EXIT(portmod_common_control_phy_timesync_set(&phy_access, config, value)); 8184 8185 if (config == SOC_PORT_CONTROL_PHY_TIMESYNC_TIMESTAMP_ADJUST) { 8186 _SOC_IF_ERR_EXIT(phymod_timesync_enable_set(&phy_access, flags, 1)); 8187 /* Wait for one AM spacing time */ 8188 sal_usleep(500); 8189 } 8190 exit: 8191 SOC_FUNC_RETURN; 8192 } 8193 8194 int pm8x50_port_control_phy_timesync_get(int unit, 8195 int port, pm_info_t pm_info, 8196 portmod_port_control_phy_timesync_t config, 8197 uint64* value) 8198 { 8199 portmod_access_get_params_t params; 8200 phymod_phy_access_t phy_access; 8201 int nof_phys; 8202 8203 SOC_INIT_FUNC_DEFS; 8204 8205 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8206 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8207 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8208 8209 _SOC_IF_ERR_EXIT(portmod_common_control_phy_timesync_get(&phy_access, config, value)); 8210 8211 exit: 8212 SOC_FUNC_RETURN; 8213 } 8214 8215 /*"port timesync config set/get"*/ 8216 int pm8x50_port_timesync_config_set(int unit, int port, pm_info_t pm_info, 8217 const portmod_phy_timesync_config_t* config) 8218 { 8219 int port_index, ts_enable_port_count; 8220 uint32 bitmap, one_step_req, is_one_step = 0, flags = 0; 8221 portmod_access_get_params_t params; 8222 phymod_phy_access_t phy_access; 8223 int nof_phys, enable, is_enable; 8224 SOC_INIT_FUNC_DEFS; 8225 8226 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 8227 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8228 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8229 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8230 8231 enable = (config->flags & SOC_PORT_PHY_TIMESYNC_ENABLE) ? 1 : 0; 8232 8233 _SOC_IF_ERR_EXIT(PM8x50_TIMESYNC_ENABLE_GET(unit, pm_info, &is_enable, port_index)); 8234 _SOC_IF_ERR_EXIT(PM8x50_TS_ENABLE_PORT_COUNT_GET(unit, pm_info, &ts_enable_port_count)); 8235 8236 if (!enable) { 8237 /* Disable 1588 */ 8238 if (is_enable) { 8239 /* If 1588 is currently enabled on the port */ 8240 /* 1. Disable One Stpe pipeline if it is enabled. */ 8241 PHYMOD_TIMESYNC_ENABLE_F_ONE_STEP_PIPELINE_SET(flags); 8242 _SOC_IF_ERR_EXIT(phymod_timesync_enable_get(&phy_access, flags, &is_one_step)); 8243 if (!is_one_step) { 8244 flags = 0; 8245 } 8246 8247 /* 2. Disable RX timestamp. */ 8248 PHYMOD_TIMESYNC_ENABLE_F_RX_SET(flags); 8249 8250 ts_enable_port_count--; 8251 /* 3. Disable FCLK if no port will using 1588 on the PM. */ 8252 if (ts_enable_port_count == 0) { 8253 PHYMOD_TIMESYNC_ENABLE_F_CORE_SET(flags); 8254 } 8255 8256 _SOC_IF_ERR_EXIT(phymod_timesync_enable_set(&phy_access, flags, 0)); 8257 } 8258 } else { 8259 /* Enable 1588 */ 8260 if (is_enable) { 8261 /* Clear current 1588 configs if the port has 1588 enabled */ 8262 PHYMOD_TIMESYNC_ENABLE_F_RX_SET(flags); 8263 PHYMOD_TIMESYNC_ENABLE_F_ONE_STEP_PIPELINE_SET(flags); 8264 _SOC_IF_ERR_EXIT(phymod_timesync_enable_set(&phy_access, flags, 0)); 8265 flags = 0; 8266 } else { 8267 /* 1588 is not enabled on the port */ 8268 if (ts_enable_port_count == 0) { 8269 /* This is the first 1588 port on the PM */ 8270 PHYMOD_TIMESYNC_ENABLE_F_CORE_SET(flags); 8271 } 8272 ts_enable_port_count++; 8273 } 8274 8275 one_step_req = (config->flags & SOC_PORT_PHY_TIMESYNC_ONE_STEP_ENABLE) ? 1 : 0; 8276 if (one_step_req) { 8277 PHYMOD_TIMESYNC_ENABLE_F_ONE_STEP_PIPELINE_SET(flags); 8278 } 8279 8280 /* Rx enable can only be done on link up as per programming requirement */ 8281 _SOC_IF_ERR_EXIT(phymod_timesync_enable_set(&phy_access, flags, 1)); 8282 8283 } 8284 8285 /* Update Timesync Enable Status in WB */ 8286 _SOC_IF_ERR_EXIT(PM8x50_TS_ENABLE_PORT_COUNT_SET(unit, pm_info, ts_enable_port_count)); 8287 _SOC_IF_ERR_EXIT(PM8x50_TIMESYNC_ENABLE_SET(unit, pm_info, enable, port_index)); 8288 8289 exit: 8290 SOC_FUNC_RETURN; 8291 } 8292 8293 int pm8x50_port_timesync_config_get(int unit, int port, pm_info_t pm_info, 8294 portmod_phy_timesync_config_t* config) 8295 { 8296 portmod_access_get_params_t params; 8297 phymod_phy_access_t phy_access; 8298 int nof_phys, timesync_enable; 8299 int port_index; 8300 uint32 bitmap, is_one_step, flags = 0; 8301 SOC_INIT_FUNC_DEFS; 8302 8303 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 8304 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8305 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8306 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8307 8308 _SOC_IF_ERR_EXIT(PM8x50_TIMESYNC_ENABLE_GET(unit, pm_info, ×ync_enable, port_index)); 8309 PHYMOD_TIMESYNC_ENABLE_F_ONE_STEP_PIPELINE_SET(flags); 8310 _SOC_IF_ERR_EXIT(phymod_timesync_enable_get(&phy_access, flags, &is_one_step)); 8311 config->flags |= is_one_step? SOC_PORT_PHY_TIMESYNC_ONE_STEP_ENABLE : 0; 8312 config->flags |= timesync_enable ? SOC_PORT_PHY_TIMESYNC_ENABLE : 0; 8313 8314 exit: 8315 SOC_FUNC_RETURN; 8316 } 8317 8318 /*"port timesync enable set/get"*/ 8319 int pm8x50_port_timesync_enable_set(int unit, int port, 8320 pm_info_t pm_info, 8321 uint32 enable) 8322 { 8323 8324 return (SOC_E_NONE); 8325 } 8326 int pm8x50_port_timesync_enable_get(int unit, int port, 8327 pm_info_t pm_info, 8328 uint32* enable) 8329 { 8330 8331 return (SOC_E_NONE); 8332 } 8333 8334 /*"port timesync nco addend set/get"*/ 8335 int pm8x50_port_timesync_nco_addend_set(int unit, int port, 8336 pm_info_t pm_info, 8337 uint32 freq_step) 8338 { 8339 8340 return (SOC_E_NONE); 8341 } 8342 int pm8x50_port_timesync_nco_addend_get(int unit, int port, 8343 pm_info_t pm_info, 8344 uint32* freq_step) 8345 { 8346 8347 return (SOC_E_NONE); 8348 } 8349 8350 /*"port timesync framesync info set/get"*/ 8351 int pm8x50_port_timesync_framesync_mode_set(int unit, 8352 int port, pm_info_t pm_info, 8353 const portmod_timesync_framesync_t* framesync) 8354 { 8355 8356 return (SOC_E_NONE); 8357 } 8358 int pm8x50_port_timesync_framesync_mode_get(int unit, 8359 int port, pm_info_t pm_info, 8360 portmod_timesync_framesync_t* framesync) 8361 { 8362 8363 return (SOC_E_NONE); 8364 } 8365 8366 /*"port timesync local time set/get"*/ 8367 int pm8x50_port_timesync_local_time_set(int unit, int port, 8368 pm_info_t pm_info, 8369 uint64 local_time) 8370 { 8371 8372 return (SOC_E_NONE); 8373 } 8374 int pm8x50_port_timesync_local_time_get(int unit, int port, 8375 pm_info_t pm_info, 8376 uint64* local_time) 8377 { 8378 8379 return (SOC_E_NONE); 8380 } 8381 8382 /*"port timesync framesync info set/get"*/ 8383 int pm8x50_port_timesync_load_ctrl_set(int unit, int port, pm_info_t pm_info, 8384 uint32 load_once, uint32 load_always) 8385 { 8386 8387 return (SOC_E_NONE); 8388 } 8389 int pm8x50_port_timesync_load_ctrl_get(int unit, int port, pm_info_t pm_info, 8390 uint32* load_once, uint32* load_always) 8391 { 8392 8393 return (SOC_E_NONE); 8394 } 8395 8396 /*"port timesync tx timestamp offset set/get"*/ 8397 int pm8x50_port_timesync_tx_timestamp_offset_set(int unit, int port, 8398 pm_info_t pm_info, 8399 uint32 ts_offset) 8400 { 8401 8402 return (SOC_E_NONE); 8403 } 8404 int pm8x50_port_timesync_tx_timestamp_offset_get(int unit, int port, 8405 pm_info_t pm_info, 8406 uint32* ts_offset) 8407 { 8408 8409 return (SOC_E_NONE); 8410 } 8411 8412 /*"port timesync rx timestamp offset set/get"*/ 8413 int pm8x50_port_timesync_rx_timestamp_offset_set(int unit, int port, 8414 pm_info_t pm_info, 8415 uint32 ts_offset) 8416 { 8417 8418 return (SOC_E_NONE); 8419 } 8420 int pm8x50_port_timesync_rx_timestamp_offset_get(int unit, int port, 8421 pm_info_t pm_info, 8422 uint32* ts_offset) 8423 { 8424 8425 return (SOC_E_NONE); 8426 } 8427 8428 /*set/get interrupt enable value. */ 8429 int pm8x50_port_interrupt_enable_set(int unit, int port, 8430 pm_info_t pm_info, 8431 int intr_type, uint32 val) 8432 { 8433 uint32 reg_val; 8434 int phy_acc; 8435 SOC_INIT_FUNC_DEFS; 8436 8437 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 8438 _SOC_IF_ERR_EXIT(READ_CDPORT_INTR_ENABLEr(unit, phy_acc, ®_val)); 8439 8440 switch(intr_type) { 8441 case portmodIntrTypeLinkdown: 8442 soc_reg_field_set(unit, CDPORT_INTR_ENABLEr, ®_val, LINK_DOWNf, val); 8443 break; 8444 case portmodIntrTypeMacErr: 8445 soc_reg_field_set(unit, CDPORT_INTR_ENABLEr, ®_val, MAC_ERRf, val); 8446 break; 8447 case portmodIntrTypeTscCore0Err: 8448 soc_reg_field_set(unit, CDPORT_INTR_ENABLEr, ®_val, TSC_CORE0_ERRf, val); 8449 break; 8450 case portmodIntrTypeTscCore1Err: 8451 soc_reg_field_set(unit, CDPORT_INTR_ENABLEr, ®_val, TSC_CORE1_ERRf, val); 8452 break; 8453 case portmodIntrTypePmdErr: 8454 soc_reg_field_set(unit, CDPORT_INTR_ENABLEr, ®_val, PMD_ERRf, val); 8455 break; 8456 case portmodIntrTypeFcReqFull: 8457 soc_reg_field_set(unit, CDPORT_INTR_ENABLEr, ®_val, FLOWCONTROL_REQ_FULLf, val); 8458 break; 8459 case portmodIntrTypeTxPktUnderflow: 8460 case portmodIntrTypeTxPktOverflow: 8461 case portmodIntrTypeTxCdcSingleBitErr: 8462 case portmodIntrTypeTxCdcDoubleBitErr: 8463 case portmodIntrTypeLocalFaultStatus: 8464 case portmodIntrTypeRemoteFaultStatus: 8465 case portmodIntrTypeLinkInterruptionStatus: 8466 case portmodIntrTypeMibMemSingleBitErr: 8467 case portmodIntrTypeMibMemDoubleBitErr: 8468 case portmodIntrTypeMibMemMultipleBitErr: 8469 _SOC_IF_ERR_EXIT(cdmac_interrupt_enable_set(unit, port, intr_type, val)); 8470 break; 8471 default: 8472 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Invalid interrupt type"))); 8473 break; 8474 } 8475 _SOC_IF_ERR_EXIT(WRITE_CDPORT_INTR_ENABLEr(unit, phy_acc, reg_val)); 8476 8477 exit: 8478 SOC_FUNC_RETURN; 8479 } 8480 8481 STATIC 8482 int _pm8x50_phy_timesync_tx_info_get(int unit, int port, pm_info_t pm_info, portmod_fifo_status_t* tx_info) 8483 { 8484 phymod_phy_access_t phy_access; 8485 int nof_phys; 8486 portmod_access_get_params_t params; 8487 phymod_ts_fifo_status_t phy_ts_tx_info; 8488 SOC_INIT_FUNC_DEFS; 8489 8490 _SOC_IF_ERR_EXIT(phymod_ts_fifo_status_t_init(&phy_ts_tx_info)); 8491 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8492 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8493 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8494 8495 _SOC_IF_ERR_EXIT(phymod_timesync_tx_info_get(&phy_access, &phy_ts_tx_info)); 8496 8497 tx_info->timestamps_in_fifo = phy_ts_tx_info.ts_in_fifo_lo; 8498 tx_info->timestamps_in_fifo_hi = phy_ts_tx_info.ts_in_fifo_hi; 8499 tx_info->sequence_id = phy_ts_tx_info.ts_seq_id; 8500 tx_info->timestamp_sub_nanosec = phy_ts_tx_info.ts_sub_nanosec; 8501 8502 exit: 8503 SOC_FUNC_RETURN; 8504 } 8505 8506 /*! 8507 * pm8x50_port_timesync_tx_info_get 8508 * 8509 * @brief get port timestamps in fifo 8510 * 8511 * @param [in] unit - unit id 8512 * @param [in] port - logical port 8513 * @param [inout] tx_info - timestamp and seq id form fifo 8514 */ 8515 8516 int pm8x50_port_timesync_tx_info_get(int unit, int port, pm_info_t pm_info, portmod_fifo_status_t* tx_info) 8517 { 8518 SOC_INIT_FUNC_DEFS; 8519 8520 _SOC_IF_ERR_EXIT(_pm8x50_phy_timesync_tx_info_get(unit, port, pm_info, tx_info)); 8521 8522 exit: 8523 SOC_FUNC_RETURN; 8524 } 8525 8526 int pm8x50_port_interrupt_enable_get(int unit, int port, 8527 pm_info_t pm_info, 8528 int intr_type, uint32* val) 8529 { 8530 uint32 reg_val; 8531 int phy_acc; 8532 SOC_INIT_FUNC_DEFS; 8533 8534 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 8535 _SOC_IF_ERR_EXIT(READ_CDPORT_INTR_ENABLEr(unit, phy_acc, ®_val)); 8536 8537 switch(intr_type) { 8538 case portmodIntrTypeLinkdown: 8539 *val = soc_reg_field_get(unit, CDPORT_INTR_ENABLEr, reg_val, LINK_DOWNf); 8540 break; 8541 case portmodIntrTypeMacErr: 8542 *val = soc_reg_field_get(unit, CDPORT_INTR_ENABLEr, reg_val, MAC_ERRf); 8543 break; 8544 case portmodIntrTypeTscCore0Err: 8545 *val = soc_reg_field_get(unit, CDPORT_INTR_ENABLEr, reg_val, TSC_CORE0_ERRf); 8546 break; 8547 case portmodIntrTypeTscCore1Err: 8548 *val = soc_reg_field_get(unit, CDPORT_INTR_ENABLEr, reg_val, TSC_CORE1_ERRf); 8549 break; 8550 case portmodIntrTypePmdErr: 8551 *val = soc_reg_field_get(unit, CDPORT_INTR_ENABLEr, reg_val, PMD_ERRf); 8552 break; 8553 case portmodIntrTypeFcReqFull: 8554 *val = soc_reg_field_get(unit, CDPORT_INTR_ENABLEr, reg_val, FLOWCONTROL_REQ_FULLf); 8555 break; 8556 case portmodIntrTypeTxPktUnderflow: 8557 case portmodIntrTypeTxPktOverflow: 8558 case portmodIntrTypeTxCdcSingleBitErr: 8559 case portmodIntrTypeTxCdcDoubleBitErr: 8560 case portmodIntrTypeLocalFaultStatus: 8561 case portmodIntrTypeRemoteFaultStatus: 8562 case portmodIntrTypeLinkInterruptionStatus: 8563 case portmodIntrTypeMibMemSingleBitErr: 8564 case portmodIntrTypeMibMemDoubleBitErr: 8565 case portmodIntrTypeMibMemMultipleBitErr: 8566 _SOC_IF_ERR_EXIT(cdmac_interrupt_enable_get(unit, port, intr_type, val)); 8567 break; 8568 default: 8569 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Invalid interrupt type"))); 8570 break; 8571 } 8572 8573 exit: 8574 SOC_FUNC_RETURN; 8575 } 8576 8577 /*get interrupt status value. */ 8578 int pm8x50_port_interrupt_get(int unit, int port, pm_info_t pm_info, int intr_type, uint32* val) 8579 { 8580 uint32 reg_val; 8581 int phy_acc; 8582 SOC_INIT_FUNC_DEFS; 8583 8584 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 8585 _SOC_IF_ERR_EXIT(READ_CDPORT_INTR_STATUSr(unit, phy_acc, ®_val)); 8586 8587 switch(intr_type) { 8588 case portmodIntrTypeLinkdown: 8589 *val = soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, LINK_DOWNf); 8590 break; 8591 case portmodIntrTypeMacErr: 8592 *val = soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, MAC_ERRf); 8593 break; 8594 case portmodIntrTypeTscCore0Err: 8595 *val = soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, TSC_CORE0_ERRf); 8596 break; 8597 case portmodIntrTypeTscCore1Err: 8598 *val = soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, TSC_CORE1_ERRf); 8599 break; 8600 case portmodIntrTypePmdErr: 8601 *val = soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, PMD_ERRf); 8602 break; 8603 case portmodIntrTypeFcReqFull: 8604 *val = soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, FLOWCONTROL_REQ_FULLf); 8605 break; 8606 case portmodIntrTypeTxPktUnderflow: 8607 case portmodIntrTypeTxPktOverflow: 8608 case portmodIntrTypeTxCdcSingleBitErr: 8609 case portmodIntrTypeTxCdcDoubleBitErr: 8610 case portmodIntrTypeLocalFaultStatus: 8611 case portmodIntrTypeRemoteFaultStatus: 8612 case portmodIntrTypeLinkInterruptionStatus: 8613 case portmodIntrTypeMibMemSingleBitErr: 8614 case portmodIntrTypeMibMemDoubleBitErr: 8615 case portmodIntrTypeMibMemMultipleBitErr: 8616 _SOC_IF_ERR_EXIT(cdmac_interrupt_status_get(unit, port, intr_type, val)); 8617 break; 8618 default: 8619 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Invalid interrupt type"))); 8620 break; 8621 } 8622 8623 exit: 8624 SOC_FUNC_RETURN; 8625 } 8626 8627 /*get interrupt value array. */ 8628 int pm8x50_port_interrupts_get(int unit, int port, pm_info_t pm_info, 8629 int arr_max_size, uint32* intr_arr, 8630 uint32* size) 8631 { 8632 uint32 reg_val, cnt=0; 8633 int phy_acc; 8634 uint32 mac_intr_cnt = 0; 8635 SOC_INIT_FUNC_DEFS; 8636 8637 _SOC_IF_ERR_EXIT(_pm8x50_phy_access_get(unit, port, pm_info, &phy_acc)); 8638 _SOC_IF_ERR_EXIT(READ_CDPORT_INTR_STATUSr(unit, phy_acc, ®_val)); 8639 8640 if (soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, LINK_DOWNf)) { 8641 if (cnt >= arr_max_size) { 8642 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Insufficient Array size"))); 8643 } 8644 intr_arr[cnt++] = portmodIntrTypeLinkdown; 8645 } 8646 8647 if (soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, MAC_ERRf)) { 8648 if (cnt >= arr_max_size) { 8649 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Insufficient Array size"))); 8650 } 8651 intr_arr[cnt++] = portmodIntrTypeMacErr; 8652 } 8653 8654 if (soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, TSC_CORE0_ERRf)) { 8655 if (cnt >= arr_max_size) { 8656 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Insufficient Array size"))); 8657 } 8658 intr_arr[cnt++] = portmodIntrTypeTscCore0Err; 8659 } 8660 8661 if (soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, TSC_CORE1_ERRf)) { 8662 if (cnt >= arr_max_size) { 8663 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Insufficient Array size"))); 8664 } 8665 intr_arr[cnt++] = portmodIntrTypeTscCore1Err; 8666 } 8667 8668 if (soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, PMD_ERRf)) { 8669 if (cnt >= arr_max_size) { 8670 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Insufficient Array size"))); 8671 } 8672 intr_arr[cnt++] = portmodIntrTypePmdErr; 8673 } 8674 8675 if (soc_reg_field_get(unit, CDPORT_INTR_STATUSr, reg_val, FLOWCONTROL_REQ_FULLf)) { 8676 if (cnt >= arr_max_size) { 8677 _SOC_EXIT_WITH_ERR(SOC_E_PARAM, (_SOC_MSG("Insufficient Array size"))); 8678 } 8679 intr_arr[cnt++] = portmodIntrTypeFcReqFull; 8680 } 8681 8682 _SOC_IF_ERR_EXIT(cdmac_interrupts_status_get(unit, port, (arr_max_size - cnt), (intr_arr + cnt), &mac_intr_cnt)); 8683 cnt += mac_intr_cnt; 8684 *size = cnt; 8685 8686 exit: 8687 SOC_FUNC_RETURN; 8688 } 8689 8690 /* portmod check if external phy is legacy*/ 8691 int pm8x50_port_check_legacy_phy(int unit, int port, 8692 pm_info_t pm_info, 8693 int* legacy_phy) 8694 { 8695 8696 return (SOC_E_NONE); 8697 } 8698 8699 /* portmod phy failover mode*/ 8700 int pm8x50_port_failover_mode_set(int unit, int port, 8701 pm_info_t pm_info, 8702 phymod_failover_mode_t failover) 8703 { 8704 8705 return (SOC_E_NONE); 8706 } 8707 int pm8x50_port_failover_mode_get(int unit, int port, 8708 pm_info_t pm_info, 8709 phymod_failover_mode_t* failover) 8710 { 8711 8712 return (SOC_E_NONE); 8713 } 8714 8715 /* portmod port rsv mask set*/ 8716 int pm8x50_port_mac_rsv_mask_set(int unit, int port, 8717 pm_info_t pm_info, 8718 uint32 rsv_mask) 8719 { 8720 SOC_INIT_FUNC_DEFS; 8721 8722 _SOC_IF_ERR_EXIT(cdmac_rsv_mask_set(unit, port, rsv_mask)); 8723 8724 exit: 8725 SOC_FUNC_RETURN; 8726 } 8727 8728 /* portmod restore information after warmboot*/ 8729 int pm8x50_port_warmboot_db_restore(int unit, int port, pm_info_t pm_info, 8730 const portmod_port_interface_config_t* intf_config, 8731 const portmod_port_init_config_t* init_config, 8732 phymod_operation_mode_t phy_op_mode) 8733 { 8734 8735 return (SOC_E_NONE); 8736 } 8737 8738 /* portmod port flow control config*/ 8739 int pm8x50_port_flow_control_set(int unit, int port, 8740 pm_info_t pm_info, 8741 int merge_mode_en, 8742 int parallel_fc_en) 8743 { 8744 8745 return (SOC_E_NONE); 8746 } 8747 8748 /*Portmod state for any logical port dynamixc settings*/ 8749 int pm8x50_port_update_dynamic_state(int unit, int port, 8750 pm_info_t pm_info, 8751 uint32_t port_dynamic_state) 8752 { 8753 8754 return (SOC_E_NONE); 8755 } 8756 8757 /*get phy operation mode. */ 8758 int pm8x50_port_phy_op_mode_get(int unit, int port, pm_info_t pm_info, 8759 phymod_operation_mode_t* val) 8760 { 8761 8762 return (SOC_E_NONE); 8763 } 8764 8765 /*Returns if the PortMacro associated with the port is initialized or not*/ 8766 int pm8x50_pm_is_initialized(int unit, int pm_id, pm_info_t pm_info, int* is_initialized) 8767 { 8768 int is_core_initialized = 0, rv; 8769 rv = PM8x50_IS_CORE_INITIALIZED_GET(unit, pm_info, &is_core_initialized); 8770 *is_initialized = is_core_initialized; 8771 8772 return rv; 8773 } 8774 8775 /* get the logical port bitmap of the current PM */ 8776 int pm8x50_pm_logical_pbmp_get(int unit, int pm_id, pm_info_t pm_info, 8777 portmod_pbmp_t* logical_pbmp) 8778 { 8779 int i, port; 8780 SOC_INIT_FUNC_DEFS; 8781 8782 PORTMOD_PBMP_CLEAR(*logical_pbmp); 8783 for (i = 0 ; i < MAX_PORTS_PER_PM8X50; i++) { 8784 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info, i, &port)); 8785 /* 8786 * A physical lane can be associated with a logical port number 8787 * -1 if the port was previously detached. 8788 */ 8789 if (port >= 0) { 8790 PORTMOD_PBMP_PORT_ADD(*logical_pbmp, port); 8791 } 8792 } 8793 8794 exit: 8795 SOC_FUNC_RETURN; 8796 } 8797 8798 int pm8x50_core_add(int unit, int pm_id, pm_info_t pm_info, const portmod_port_add_info_t* add_info) 8799 { 8800 int is_initialized = 0; 8801 SOC_INIT_FUNC_DEFS; 8802 8803 _SOC_IF_ERR_EXIT(pm8x50_pm_is_initialized(unit, pm_id, pm_info, &is_initialized)); 8804 8805 if (!is_initialized) { 8806 _SOC_IF_ERR_EXIT(pm8x50_pm_enable(unit, pm_id, pm_info, 1)); 8807 } 8808 8809 _SOC_IF_ERR_EXIT(pm8x50_pm_serdes_core_init(unit, pm_id, pm_info, add_info)); 8810 8811 exit: 8812 SOC_FUNC_RETURN; 8813 } 8814 8815 int pm8x50_port_lane_map_set(int unit, int port, pm_info_t pm_info, uint32 flags, const phymod_lane_map_t* lane_map) 8816 { 8817 8818 return (SOC_E_UNAVAIL); 8819 } 8820 8821 int pm8x50_port_lane_map_get(int unit, int port, pm_info_t pm_info, uint32 flags, phymod_lane_map_t* lane_map) 8822 { 8823 SOC_INIT_FUNC_DEFS; 8824 8825 *lane_map = PM_8x50_INFO(pm_info)->lane_map; 8826 8827 SOC_FUNC_RETURN; 8828 } 8829 8830 int pm8x50_port_synce_clk_ctrl_set(int unit, int port, pm_info_t pm_info, 8831 const portmod_port_synce_clk_ctrl_t* cfg) 8832 { 8833 phymod_synce_clk_ctrl_t phy_synce_cfg; 8834 portmod_access_get_params_t params; 8835 phymod_phy_access_t phy_access; 8836 int nof_phys; 8837 int config_valid = 0; 8838 8839 SOC_INIT_FUNC_DEFS; 8840 8841 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8842 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8843 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8844 8845 phymod_synce_clk_ctrl_t_init(&phy_synce_cfg); 8846 phy_synce_cfg.stg0_mode = cfg->stg0_mode; 8847 phy_synce_cfg.stg1_mode = cfg->stg1_mode; 8848 phy_synce_cfg.sdm_val = cfg->sdm_val; 8849 8850 /* next validate the stage0/1 config */ 8851 /* first check legacy mode */ 8852 if (cfg->stg0_mode == 0x0) { 8853 config_valid = 1; 8854 } else if ((cfg->stg0_mode == 0x1) && (cfg->stg1_mode == 0x2)) { 8855 config_valid = 1; 8856 } else if ((cfg->stg0_mode == 0x2) && (cfg->stg1_mode == 0x0)) { 8857 config_valid = 1; 8858 } 8859 8860 if (config_valid) { 8861 _SOC_IF_ERR_EXIT(phymod_phy_synce_clk_ctrl_set(&phy_access, 8862 phy_synce_cfg)); 8863 } else { 8864 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 8865 (_SOC_MSG("SyncE config is not valid \n"))); 8866 } 8867 8868 exit: 8869 SOC_FUNC_RETURN; 8870 } 8871 8872 int pm8x50_port_synce_clk_ctrl_get(int unit, int port, pm_info_t pm_info, 8873 portmod_port_synce_clk_ctrl_t* cfg) 8874 { 8875 phymod_synce_clk_ctrl_t phy_synce_cfg; 8876 portmod_access_get_params_t params; 8877 phymod_phy_access_t phy_access; 8878 int nof_phys; 8879 8880 SOC_INIT_FUNC_DEFS; 8881 8882 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 8883 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 8884 ¶ms, 1, &phy_access, &nof_phys, NULL)); 8885 8886 phymod_synce_clk_ctrl_t_init(&phy_synce_cfg); 8887 8888 _SOC_IF_ERR_EXIT(phymod_phy_synce_clk_ctrl_get(&phy_access, 8889 &phy_synce_cfg)); 8890 8891 cfg->stg0_mode = phy_synce_cfg.stg0_mode; 8892 cfg->stg1_mode = phy_synce_cfg.stg1_mode; 8893 cfg->sdm_val = phy_synce_cfg.sdm_val; 8894 8895 exit: 8896 SOC_FUNC_RETURN; 8897 } 8898 8899 STATIC 8900 int _pm8x50_pm_tsc_interrupt_type_get(int unit, int intr_val, uint32 flags, 8901 pm8x50_tsc_err_intr_phymod_map_t *tsc_intr_info) 8902 { 8903 pm8x50_tsc_intr_type_t iter = pm8x50TscIntrEccNone; 8904 pm8x50_tsc_intr_type_t iter_start = pm8x50TscIntrEccNone; 8905 pm8x50_tsc_intr_type_t iter_end = pm8x50TscIntrEccNone; 8906 8907 /* Check is 1-bit or 2-bit ECC interrupt type */ 8908 if (flags & PM8x50_TSC_ECC_1B_INTR) { 8909 iter_start = pm8x50TscIntrEcc1bErr; 8910 iter_end = pm8x50TscIntrEcc1bErrCount; 8911 } else if (flags & PM8x50_TSC_ECC_2B_INTR) { 8912 iter_start = pm8x50TscIntrEcc2bErr; 8913 iter_end = pm8x50TscIntrEcc2bErrCount; 8914 } else { 8915 return SOC_E_INTERNAL; 8916 } 8917 8918 for(iter = iter_start; iter <= iter_end; iter++) { 8919 if (intr_val & pm8x50_tsc_ecc_intr_info[iter].flags) { 8920 /* return phymod tsc interrupt type */ 8921 sal_memcpy(tsc_intr_info, &pm8x50_tsc_ecc_intr_info[iter], 8922 sizeof(pm8x50_tsc_err_intr_phymod_map_t)); 8923 break; 8924 } 8925 } 8926 8927 return SOC_E_NONE; 8928 } 8929 8930 int pm8x50_pm_interrupt_process(int unit, int pm_id, pm_info_t pm_info, 8931 portmod_ecc_intr_info_t *ecc_info) 8932 { 8933 int i = 0, ii = 0, j = 0; 8934 int lport = 0; 8935 int prev_lport = 0; 8936 int first_lport = 0; 8937 uint32 val = 0, rval = 0, fval = 0; 8938 uint32 tsc_intr_flags = 0x0, is_handled = 0; 8939 uint64 rval64; 8940 pm8x50_tsc_err_intr_phymod_map_t tsc_intr_info; 8941 portmod_pm_intr_info_t *p_intr_info = &pm8x50_pm_intr_info[0]; 8942 portmod_intr_reg_info_t *p_intr_grp_info = NULL; 8943 portmod_intr_type_t intr_type; 8944 phymod_phy_access_t phy_access; 8945 portmod_access_get_params_t params; 8946 int nof_phys = 0; 8947 int is_intr_found = 0; 8948 SOC_INIT_FUNC_DEFS; 8949 8950 COMPILER_64_ZERO(rval64); 8951 /* Get the first physical port of the pm core */ 8952 for(ii=0; ii < PM8X50_LANES_PER_CORE; ii++) { 8953 /* get the logical port associated with the physical port */ 8954 _SOC_IF_ERR_EXIT(PM8x50_LANE2PORT_GET(unit, pm_info, ii, &lport)); 8955 8956 /* skip if invalid or its the same logical port */ 8957 if ((lport == -1) || (prev_lport == lport)) { 8958 /*LOG_CLI(("Port(%s) - Skipping interrupt processing for same logical port!\n", 8959 SOC_PORT_NAME(unit, lport)));*/ 8960 continue; 8961 } 8962 8963 /* Remember the first port */ 8964 if (first_lport == 0) { 8965 first_lport = lport; 8966 } 8967 prev_lport = lport; 8968 8969 /* 8970 * Following is the sequence for processing the interrupts. 8971 * 1. Check the top level interrupt status register of the 8972 * PM8x50 to determine if its a MAC interrupt or a 8973 * TSC interrupti, 8974 * 2. If its a MAC interrupt, MAC interrupt status register 8975 * is read, to determine the MAC interrupt type, This is 8976 * is a per-port register and the function returns on the 8977 * determining the first interrupt. 8978 * 3. If its a TSC interrupt, the TSC interrupt status 8979 * register is read to determine the TSC inetrrupt type. 8980 */ 8981 8982 /* 8983 * Read the top level interrupt status only once, since its 8984 * only a single copy register. 8985 */ 8986 if (first_lport == prev_lport) { 8987 for (i = 0; i < sizeof(pm8x50_pm_intr_info)/ 8988 sizeof(portmod_pm_intr_info_t); i++) { 8989 p_intr_info = &pm8x50_pm_intr_info[i]; 8990 intr_type = p_intr_info->intr_type; 8991 _SOC_IF_ERR_EXIT(pm8x50_port_interrupt_get(unit, lport, 8992 pm_info, intr_type, &val)); 8993 8994 /* continue if interrupt is not set. */ 8995 if (!val) { 8996 continue; 8997 } 8998 8999 /* Either MAC, TSC, PMD Interrupt is set, */ 9000 /* 9001 * Iterate through the individual interrupt status 9002 * based on the list of status registers. 9003 */ 9004 if (p_intr_info->is_intr_status_group) { 9005 p_intr_grp_info = &p_intr_info->intr_list_status_reg[0]; 9006 intr_type = p_intr_grp_info->intr_type; 9007 is_intr_found = 1; 9008 } 9009 /*LOG_CLI(("%s\n", p_intr_info->mem_str));*/ 9010 break; 9011 } 9012 9013 if (!is_intr_found) { 9014 _SOC_EXIT_WITH_ERR(SOC_E_INTERNAL, 9015 (_SOC_MSG("Port(%s) - Interrupt not found!\n"), 9016 SOC_PORT_NAME(unit, lport))); 9017 } 9018 9019 /* 9020 * Below logic determines the specific interrupt type 9021 * in MAC, TSC Core0, TSC Core1, 9022 */ 9023 while (intr_type != portmodIntrTypeCount) { 9024 if (SOC_REG_IS_64(unit, p_intr_grp_info->st_reg)) { 9025 uint64 fval64; 9026 9027 _SOC_IF_ERR_EXIT(soc_reg64_get(unit, 9028 p_intr_grp_info->st_reg, 9029 lport, 0, &rval64)); 9030 fval64 = soc_reg64_field_get(unit, p_intr_grp_info->st_reg, 9031 rval64, p_intr_grp_info->st_fld); 9032 COMPILER_64_TO_32_LO(fval, fval64); 9033 } else { 9034 _SOC_IF_ERR_EXIT(soc_reg32_get(unit, 9035 p_intr_grp_info->st_reg, 9036 lport, 0, &rval)); 9037 fval = soc_reg_field_get(unit, p_intr_grp_info->st_reg, 9038 rval, p_intr_grp_info->st_fld); 9039 } 9040 9041 /* If not set skip to the next interrupt type. */ 9042 if (!fval) { 9043 j++; 9044 p_intr_grp_info = &p_intr_info->intr_list_status_reg[j]; 9045 intr_type = p_intr_info->intr_list_status_reg[j].intr_type; 9046 continue; 9047 } 9048 9049 LOG_VERBOSE(BSL_LS_SOC_PORT, (BSL_META_U(unit, "Port - %s " 9050 "Reg - %s, Field - %s fval - %d\n"), 9051 SOC_PORT_NAME(unit, lport), 9052 SOC_REG_NAME(unit, p_intr_grp_info->st_reg), 9053 SOC_FIELD_NAME(unit, p_intr_grp_info->st_fld), fval)); 9054 9055 /* If interrupt status is set, and status is clear-on-read */ 9056 if (p_intr_grp_info->flags & PORTMOD_INTR_STATUS_COR) { 9057 9058 /* If its per-port clear status register */ 9059 if (!(p_intr_grp_info->flags & 9060 PORTMOD_INTR_BLOCK_CLEAR_REG)) { 9061 _SOC_IF_ERR_EXIT(soc_reg32_get(unit, 9062 p_intr_grp_info->clr_reg, 9063 lport, 0, &rval)); 9064 LOG_ERROR(BSL_LS_SOC_PORT, 9065 (BSL_META_U(unit, "NOT BLOCK_CLEAR_REG\n"))); 9066 } else { 9067 /* If its per-port clear status register */ 9068 uint32 raddr; 9069 int phy_port, block; 9070 uint8 at; 9071 9072 PORTMOD_PBMP_ITER(PM_8x50_INFO(pm_info)->phys, 9073 phy_port) { 9074 break; 9075 } 9076 9077 raddr = soc_reg_addr_get(unit, 9078 p_intr_grp_info->clr_reg, phy_port, 0, 9079 SOC_REG_ADDR_OPTION_PRESERVE_PORT, 9080 &block, &at); 9081 _SOC_IF_ERR_EXIT(_soc_reg32_get(unit, block, at, 9082 raddr, &rval)); 9083 LOG_CLI(("BLOCK_CLEAR_REG\n")); 9084 } 9085 9086 fval = soc_reg_field_get(unit, 9087 p_intr_grp_info->clr_reg, 9088 rval, p_intr_grp_info->clr_fld); 9089 } else if (((intr_type == portmodIntrTypeTscCore0Err) || 9090 (intr_type == portmodIntrTypeTscCore1Err)) && 9091 (p_intr_grp_info->flags & 9092 PORTMOD_INTR_STATUS_W1TC)) { 9093 9094 if (p_intr_grp_info->st_fld == TSC_ECC_1B_ERRf) { 9095 tsc_intr_flags = PM8x50_TSC_ECC_1B_INTR; 9096 } else if (p_intr_grp_info->st_fld == TSC_ECC_2B_ERRf) { 9097 tsc_intr_flags = PM8x50_TSC_ECC_2B_INTR; 9098 } 9099 _SOC_IF_ERR_EXIT(_pm8x50_pm_tsc_interrupt_type_get(unit, 9100 fval, tsc_intr_flags, 9101 &tsc_intr_info)); 9102 /* Only internal phy supported. */ 9103 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, 9104 ¶ms)); 9105 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, 9106 lport, pm_info, ¶ms, 1, 9107 &phy_access, &nof_phys, NULL)); 9108 9109 LOG_VERBOSE(BSL_LS_SOC_PORT, 9110 (BSL_META_U(unit, "TSC Core Error - %d\n"), 9111 tsc_intr_info.phymod_intr_map)); 9112 /* clear tsc interrupt */ 9113 _SOC_IF_ERR_EXIT(phymod_intr_handler(&phy_access, 9114 tsc_intr_info.phymod_intr_map, 9115 &is_handled)); 9116 if (!is_handled) { 9117 /*LOG_CLI(("Cannot handle - %s\n", tsc_intr_info.str));*/ 9118 } else { 9119 /*LOG_CLI(("Phymod interrupt handled - %d(%s)\n", 9120 is_handled, tsc_intr_info.str));*/ 9121 } 9122 ecc_info->mem_str = tsc_intr_info.str; 9123 } 9124 9125 ecc_info->port = lport; 9126 ecc_info->ecc_num_bits_err = 9127 (p_intr_grp_info->flags & PORTMOD_INTR_ECC_1B_ERR) ? 9128 PORTMOD_INTR_ECC_1B_ERR: 9129 (p_intr_grp_info->flags & PORTMOD_INTR_ECC_2B_ERR) ? 9130 PORTMOD_INTR_ECC_2B_ERR: 9131 (p_intr_grp_info->flags & PORTMOD_INTR_ECC_MULTIB_ERR) ? 9132 PORTMOD_INTR_ECC_MULTIB_ERR: PORTMOD_PM_ECC_ERR_NONE; 9133 SOC_EXIT; 9134 } /* intr_type != portmodIntrTypeCount */ 9135 } /* Interate through the interrupt types */ 9136 } /* Iterate through logical ports */ 9137 9138 exit: 9139 SOC_FUNC_RETURN; 9140 } 9141 9142 int pm8x50_pm_core_num_get(int unit, pm_info_t pm_info, int* core_num) 9143 { 9144 *core_num = PM_8x50_INFO(pm_info)->core_num; 9145 return (SOC_E_NONE); 9146 } 9147 9148 int _portmod_rlm_config_validate(int unit, int port, int speed, int port_index, uint32 active_lane_map) 9149 { 9150 int i, num_lane = 8, active_lane_num = 0; 9151 SOC_INIT_FUNC_DEFS; 9152 9153 for (i = 0; i < num_lane; i++) { 9154 if (active_lane_map & 1 << (port_index + i)) { 9155 active_lane_num++; 9156 } 9157 } 9158 9159 /* first check 200G case */ 9160 switch (speed) { 9161 case 150000: 9162 if ((active_lane_map != 0xf0) && (active_lane_map != 0xf)) { 9163 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 9164 (_SOC_MSG("Active lane map is not valid"))); 9165 } 9166 break; 9167 case 200000: 9168 if (active_lane_num != 3) { 9169 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 9170 (_SOC_MSG("Active lane map is not valid"))); 9171 } else if ((port_index == 0) && (active_lane_map & 0xf0)) { 9172 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 9173 (_SOC_MSG("Active lane map is not valid"))); 9174 } else if ((port_index == 4) && (active_lane_map & 0x0f)) { 9175 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 9176 (_SOC_MSG("Active lane map is not valid"))); 9177 } 9178 break; 9179 case 300000: 9180 case 350000: 9181 if (active_lane_map != 0xff) { 9182 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 9183 (_SOC_MSG("Active lane map is not valid"))); 9184 } 9185 break; 9186 case 400000: 9187 if ((active_lane_num != 6) && (active_lane_num != 7)) { 9188 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 9189 (_SOC_MSG("Active lane map is not valid"))); 9190 } 9191 break; 9192 default: 9193 break; 9194 } 9195 exit: 9196 SOC_FUNC_RETURN; 9197 9198 } 9199 9200 int pm8x50_port_rlm_config_set(int unit, int port, pm_info_t pm_info, 9201 int enable, 9202 const portmod_port_rlm_config_t* rlm_config) 9203 { 9204 portmod_access_get_params_t params; 9205 phymod_phy_access_t phy_access; 9206 uint32_t is_initiator, pcs_is_reconfigured, active_lane_map_local; 9207 phymod_fec_type_t FecType; 9208 uint32_t txLaneSwap, rxLaneSwap, bitmap, port_lane_mask; 9209 portmod_port_rlm_state_t local_port_rlm_state; 9210 int nof_phys, port_index = -1, rlm_enabled; 9211 phymod_phy_speed_config_t phy_speed_config; 9212 9213 9214 SOC_INIT_FUNC_DEFS; 9215 9216 _SOC_IF_ERR_EXIT(portmod_access_get_params_t_init(unit, ¶ms)); 9217 _SOC_IF_ERR_EXIT(pm8x50_port_phy_lane_access_get(unit, port, pm_info, 9218 ¶ms, 1, &phy_access, &nof_phys, NULL)); 9219 9220 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &port_lane_mask)); 9221 9222 /* first get the current port speed */ 9223 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_t_init(&phy_speed_config)); 9224 _SOC_IF_ERR_EXIT(phymod_phy_speed_config_get(&phy_access, &phy_speed_config)); 9225 9226 /* only 150G/300G/350G/200G/400G can enable RLM mode */ 9227 if ((phy_speed_config.data_rate == 150000) || 9228 ((phy_speed_config.data_rate == 200000) && (phy_speed_config.fec_type != phymod_fec_None)) || 9229 (phy_speed_config.data_rate == 300000) || 9230 (phy_speed_config.data_rate == 350000) || 9231 (phy_speed_config.data_rate == 400000)) { 9232 /* first get all the RLM warmboot variable */ 9233 _SOC_IF_ERR_EXIT 9234 (PM8x50_RLM_ENABLE_GET(unit, pm_info, &rlm_enabled, port_index)); 9235 9236 _SOC_IF_ERR_EXIT 9237 (PM8x50_INITIATOR_GET(unit, pm_info, &is_initiator, port_index)); 9238 9239 _SOC_IF_ERR_EXIT 9240 (PM8x50_PCS_RECONFIG_GET(unit, pm_info, &pcs_is_reconfigured, port_index)); 9241 9242 _SOC_IF_ERR_EXIT 9243 (PM8x50_ACTIVE_LANE_MAP_GET(unit, pm_info, &active_lane_map_local, port_index)); 9244 9245 _SOC_IF_ERR_EXIT 9246 (PM8x50_RLM_STATE_GET(unit, pm_info, &local_port_rlm_state.rlm_state, port_index)); 9247 9248 _SOC_IF_ERR_EXIT 9249 (PM8x50_ORIGINAL_FEC_GET(unit, pm_info, &FecType, port_index)); 9250 9251 _SOC_IF_ERR_EXIT 9252 (PM8x50_ORIG_TX_LANE_MAP_GET(unit, pm_info, &txLaneSwap)); 9253 9254 _SOC_IF_ERR_EXIT 9255 (PM8x50_ORIG_RX_LANE_MAP_GET(unit, pm_info, &rxLaneSwap)); 9256 } else { 9257 /* RLM is not supported */ 9258 _SOC_EXIT_WITH_ERR(SOC_E_CONFIG, 9259 (_SOC_MSG("RLM mode is not supported on this speed"))); 9260 } 9261 9262 /* set the rlm_enabled */ 9263 rlm_enabled = enable; 9264 9265 /* if to enable RLM */ 9266 if (enable) { 9267 is_initiator = rlm_config->is_initiator; 9268 /* set the RLM variable and state accordingly */ 9269 pcs_is_reconfigured = FALSE; 9270 /* next check if initiator is set */ 9271 /*if so need to get the active_lane_map */ 9272 if (is_initiator) { 9273 _SOC_IF_ERR_EXIT(_portmod_rlm_config_validate(unit, port, 9274 phy_speed_config.data_rate, 9275 port_index, 9276 rlm_config->active_lane_bit_map)); 9277 active_lane_map_local = rlm_config->active_lane_bit_map; 9278 } else { 9279 active_lane_map_local = 0x0; 9280 } 9281 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_SEND_PACKET_DATA; 9282 } else { 9283 uint32_t is_400g_port = 0, tmp_active_lane_map = 0x0f; 9284 portmod_speed_config_t local_speed_config; 9285 9286 /* is RLM disable, then clear both initiator and active lane map */ 9287 is_initiator = FALSE; 9288 active_lane_map_local = 0x0; 9289 /* need to know if 4 lane or 8 lane port and also start lane of this port */ 9290 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &bitmap)); 9291 /*next based on the port index, need to get mpp index */ 9292 if (port_index == 4) { 9293 tmp_active_lane_map = 0xf0; 9294 } else if (bitmap == 0xff) { 9295 is_400g_port = 1; 9296 tmp_active_lane_map = 0xff; 9297 } 9298 /* next need to restore the tx/rx original lane swap */ 9299 _SOC_IF_ERR_EXIT(phymod_phy_pcs_lane_swap_adjust(&phy_access, 9300 tmp_active_lane_map, 9301 txLaneSwap, 9302 rxLaneSwap)); 9303 9304 /*then disable PRBS tx/rx */ 9305 _SOC_IF_ERR_EXIT(phymod_phy_prbs_enable_set(&phy_access, 0, 0)); 9306 /* next disable all the PMD override */ 9307 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDRxLock, 0, 0)); 9308 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDSignalDetect, 0, 0)); 9309 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDTxDisable, 0, 0)); 9310 _SOC_IF_ERR_EXIT(phymod_phy_pmd_override_enable_set(&phy_access, phymodPMDLaneReset, 0, 0)); 9311 9312 /* next disable LI */ 9313 _SOC_IF_ERR_EXIT(cdmac_link_interrupt_ordered_set_enable(unit, port, 0)); 9314 9315 /* next read the current PMD lane config info */ 9316 _SOC_IF_ERR_EXIT(pm8x50_port_speed_config_get(unit, port, pm_info, &local_speed_config)); 9317 if (is_400g_port) { 9318 local_speed_config.num_lane = 8; 9319 local_speed_config.speed = 400000; 9320 } else { 9321 local_speed_config.num_lane = 4; 9322 local_speed_config.speed = 200000; 9323 } 9324 9325 /* based on the saved PHYMOD FEctype, get the portmod enum */ 9326 _SOC_IF_ERR_EXIT(_pm8x50_port_phy_to_port_fec(FecType, &local_speed_config.fec)); 9327 9328 /* then do a forced speed config to restore original speed/fec mode */ 9329 _SOC_IF_ERR_EXIT(pm8x50_port_speed_config_set(unit, port, pm_info, &local_speed_config)); 9330 9331 pcs_is_reconfigured = FALSE; 9332 active_lane_map_local = 0x0; 9333 local_port_rlm_state.rlm_state = PORTMOD_PORT_RLM_FSM_COUNT; 9334 } 9335 9336 /* finally restore all the Warm boot variables */ 9337 _SOC_IF_ERR_EXIT 9338 (PM8x50_RLM_ENABLE_SET(unit, pm_info, rlm_enabled, port_index)); 9339 9340 _SOC_IF_ERR_EXIT 9341 (PM8x50_INITIATOR_SET(unit, pm_info, is_initiator, port_index)); 9342 9343 _SOC_IF_ERR_EXIT 9344 (PM8x50_PCS_RECONFIG_SET(unit, pm_info, pcs_is_reconfigured, port_index)); 9345 9346 _SOC_IF_ERR_EXIT 9347 (PM8x50_ACTIVE_LANE_MAP_SET(unit, pm_info, active_lane_map_local, port_index)); 9348 9349 _SOC_IF_ERR_EXIT 9350 (PM8x50_RLM_STATE_SET(unit, pm_info, local_port_rlm_state.rlm_state, port_index)); 9351 9352 /* call back register should happen after RLM ENABLE is set */ 9353 if (enable) { 9354 _SOC_IF_ERR_EXIT(portmod_port_periodic_callback_register(unit, port, pm8x50_periodic_callback, PORTMOD_THREAD_INTERVAL_1s)); 9355 } 9356 9357 9358 exit: 9359 SOC_FUNC_RETURN; 9360 } 9361 9362 int pm8x50_port_rlm_config_get(int unit, int port, pm_info_t pm_info, 9363 int* enable, 9364 portmod_port_rlm_config_t* rlm_config) 9365 { 9366 uint32_t is_initiator, active_lane_map_local, port_lane_mask; 9367 int rlm_enabled, port_index; 9368 9369 SOC_INIT_FUNC_DEFS; 9370 9371 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &port_lane_mask)); 9372 9373 /* first get all the RLM warmboot variable */ 9374 _SOC_IF_ERR_EXIT 9375 (PM8x50_RLM_ENABLE_GET(unit, pm_info, &rlm_enabled, port_index)); 9376 9377 _SOC_IF_ERR_EXIT 9378 (PM8x50_INITIATOR_GET(unit, pm_info, &is_initiator, port_index)); 9379 9380 _SOC_IF_ERR_EXIT 9381 (PM8x50_ACTIVE_LANE_MAP_GET(unit, pm_info, &active_lane_map_local, port_index)); 9382 9383 *enable = rlm_enabled; 9384 rlm_config->is_initiator = is_initiator; 9385 rlm_config->active_lane_bit_map = active_lane_map_local; 9386 9387 exit: 9388 SOC_FUNC_RETURN; 9389 } 9390 9391 int pm8x50_port_rlm_status_get(int unit, int port, pm_info_t pm_info, 9392 portmod_port_rlm_status_t *rlm_status) 9393 { 9394 uint32_t rlm_state, port_lane_mask; 9395 int rlm_enabled, port_index; 9396 9397 SOC_INIT_FUNC_DEFS; 9398 9399 _SOC_IF_ERR_EXIT(_pm8x50_port_index_get(unit, port, pm_info, &port_index, &port_lane_mask)); 9400 9401 _SOC_IF_ERR_EXIT 9402 (PM8x50_RLM_ENABLE_GET(unit, pm_info, &rlm_enabled, port_index)); 9403 _SOC_IF_ERR_EXIT 9404 (PM8x50_RLM_STATE_GET(unit, pm_info, &rlm_state, port_index)); 9405 9406 /* first initialize the status */ 9407 rlm_status->rlm_disabled = !rlm_enabled; 9408 rlm_status->rlm_busy = FALSE; 9409 rlm_status->rlm_failed = FALSE; 9410 rlm_status->rlm_done = FALSE; 9411 9412 9413 /* first check rlm_state */ 9414 if (rlm_state == PORTMOD_PORT_RLM_ERROR) { 9415 rlm_status->rlm_failed = TRUE; 9416 } else if (rlm_state == PORTMOD_PORT_RLM_DONE) { 9417 rlm_status->rlm_done = TRUE; 9418 } else if ((rlm_state < PORTMOD_PORT_RLM_FSM_COUNT) && (rlm_enabled)) { 9419 rlm_status->rlm_busy = TRUE; 9420 } 9421 9422 exit: 9423 SOC_FUNC_RETURN; 9424 } 9425 #endif