portctrl.c (49394B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * portctrl soc routines 8 */ 9 #include <shared/bsl.h> 10 11 #include <sal/core/libc.h> 12 13 #include <soc/debug.h> 14 #include <soc/util.h> 15 #include <soc/mem.h> 16 #include <soc/esw/portctrl.h> 17 #include <soc/esw/portctrl_internal.h> 18 #include <soc/tomahawk3.h> 19 #include <soc/phy/phymod_sim.h> 20 #include <soc/portmod/portmod.h> 21 #include <soc/init/tomahawk3_ep_init.h> 22 23 #ifdef BCM_TOMAHAWK3_SUPPORT 24 25 /* Calculation same as PM addr calculation below, but Management PM is on Bus 11 26 * 0x80 | 0x260 | 1 27 */ 28 static uint32_t _th3_pm4x10_addr[SOC_TH3_PM4X10_COUNT] = { 0x2E1 }; 29 static uint32_t _th3_pm4x10_port[SOC_TH3_PM4X10_COUNT] = { SOC_TH3_PM4X10_PORT_1}; 30 31 /* This holds PM VCO info during the flexport operation. It is used 32 * during the validation stage to hold the VCOs prior to writing them 33 * back to SOC_INFO and flexing 34 */ 35 static soc_pmvco_info_t out_pmvco_info[SOC_MAX_NUM_BLKS]; 36 37 #define SOC_TH3_PM8X50_PORT_1 1 38 #define SOC_TH3_PM8X50_PORT_2 9 39 #define SOC_TH3_PM8X50_PORT_3 17 40 #define SOC_TH3_PM8X50_PORT_4 25 41 #define SOC_TH3_PM8X50_PORT_5 33 42 #define SOC_TH3_PM8X50_PORT_6 41 43 #define SOC_TH3_PM8X50_PORT_7 49 44 #define SOC_TH3_PM8X50_PORT_8 57 45 #define SOC_TH3_PM8X50_PORT_9 65 46 #define SOC_TH3_PM8X50_PORT_10 73 47 #define SOC_TH3_PM8X50_PORT_11 81 48 #define SOC_TH3_PM8X50_PORT_12 89 49 #define SOC_TH3_PM8X50_PORT_13 97 50 #define SOC_TH3_PM8X50_PORT_14 105 51 #define SOC_TH3_PM8X50_PORT_15 113 52 #define SOC_TH3_PM8X50_PORT_16 121 53 #define SOC_TH3_PM8X50_PORT_17 129 54 #define SOC_TH3_PM8X50_PORT_18 137 55 #define SOC_TH3_PM8X50_PORT_19 145 56 #define SOC_TH3_PM8X50_PORT_20 153 57 #define SOC_TH3_PM8X50_PORT_21 161 58 #define SOC_TH3_PM8X50_PORT_22 169 59 #define SOC_TH3_PM8X50_PORT_23 177 60 #define SOC_TH3_PM8X50_PORT_24 185 61 #define SOC_TH3_PM8X50_PORT_25 193 62 #define SOC_TH3_PM8X50_PORT_26 201 63 #define SOC_TH3_PM8X50_PORT_27 209 64 #define SOC_TH3_PM8X50_PORT_28 217 65 #define SOC_TH3_PM8X50_PORT_29 225 66 #define SOC_TH3_PM8X50_PORT_30 233 67 #define SOC_TH3_PM8X50_PORT_31 241 68 #define SOC_TH3_PM8X50_PORT_32 249 69 70 /* PM Address calculation: 71 * 0x80 | bus_id_encoding | (phy port - bus offset) 72 * where bus_id_encoding = bit {9,8,6,5} 73 * 74 * So PM0 = 0x80 | 0x0 | (1 - 0) = 0x81 75 * PM3 = 0x80 | 0x20 | (25 - 24) = 0xa1 76 * PM6 = 0x80 | 0x40 | (49 - 48) = 0xc1 77 * PM7 = 0x80 | 0x40 | (57 - 48) = 0xc9 78 * PM9 = 0x80 | 0x60 | (73 - 72) = 0xe1 79 * PM12 = 0x80 | 0x100 | (97 - 96) = 0x181 80 * PM15 = 0x80 | 0x120 | (121 - 120) = 0x1a1 81 * PM18 = 0x80 | 0x140 | (145 - 144) = 0x1c1 82 * PM21 = 0x80 | 0x160 | (169 - 168) = 0x1e1 83 * PM24 = 0x80 | 0x200 | (193 - 192) = 0x281 84 * PM27 = 0x80 | 0x220 | (217 - 216) = 0x2a1 85 * PM30 = 0x80 | 0x240 | (241 - 240) = 0x2c1 86 */ 87 static uint32_t _th3_pm8x50_addr[SOC_TH3_PM8X50_COUNT] = { 88 0x81, 0x89, 0x91, /* Bus 0 has PM 0-2 */ 89 0xa1, 0xa9, 0xb1, /* Bus 1 has PM 3-5 */ 90 0xc1, 0xc9, 0xd1, /* Bus 2 has PM 6-8 */ 91 0xe1, 0xe9, 0xf1, /* Bus 3 has PM 9-11 */ 92 0x181, 0x189, 0x191, /* Bus 4 has PM 12-14 */ 93 0x1a1, 0x1a9, 0x1b1, /* Bus 5 has PM 15-17 */ 94 0x1c1, 0x1c9, 0x1d1, /* Bus 6 has PM 18-20 */ 95 0x1e1, 0x1e9, 0x1f1, /* Bus 7 has PM 21-23 */ 96 0x281, 0x289, 0x291, /* Bus 8 has PM 24-26 */ 97 0x2a1, 0x2a9, 0x2b1, /* Bus 9 has PM 27-29 */ 98 0x2c1, 0x2c9 /* Bus 10 has PM 30-31 */ 99 }; 100 101 static uint32_t _th3_pm8x50_core_num[SOC_TH3_PM8X50_COUNT] = { 102 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 103 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 104 }; 105 106 static uint32_t _th3_pm4x10_core_num[SOC_TH3_PM4X10_COUNT] = {32}; 107 108 static uint32_t _th3_pm8x50_port[SOC_TH3_PM8X50_COUNT] = { 109 SOC_TH3_PM8X50_PORT_1, SOC_TH3_PM8X50_PORT_2, 110 SOC_TH3_PM8X50_PORT_3, SOC_TH3_PM8X50_PORT_4, 111 SOC_TH3_PM8X50_PORT_5, SOC_TH3_PM8X50_PORT_6, 112 SOC_TH3_PM8X50_PORT_7, SOC_TH3_PM8X50_PORT_8, 113 SOC_TH3_PM8X50_PORT_9, SOC_TH3_PM8X50_PORT_10, 114 SOC_TH3_PM8X50_PORT_11, SOC_TH3_PM8X50_PORT_12, 115 SOC_TH3_PM8X50_PORT_13, SOC_TH3_PM8X50_PORT_14, 116 SOC_TH3_PM8X50_PORT_15, SOC_TH3_PM8X50_PORT_16, 117 SOC_TH3_PM8X50_PORT_17, SOC_TH3_PM8X50_PORT_18, 118 SOC_TH3_PM8X50_PORT_19, SOC_TH3_PM8X50_PORT_20, 119 SOC_TH3_PM8X50_PORT_21, SOC_TH3_PM8X50_PORT_22, 120 SOC_TH3_PM8X50_PORT_23, SOC_TH3_PM8X50_PORT_24, 121 SOC_TH3_PM8X50_PORT_25, SOC_TH3_PM8X50_PORT_26, 122 SOC_TH3_PM8X50_PORT_27, SOC_TH3_PM8X50_PORT_28, 123 SOC_TH3_PM8X50_PORT_29, SOC_TH3_PM8X50_PORT_30, 124 SOC_TH3_PM8X50_PORT_31, SOC_TH3_PM8X50_PORT_32 125 }; 126 127 portmod_pm_instances_t th3_pm_types[] = { 128 #ifdef PORTMOD_PM4X10_SUPPORT 129 {portmodDispatchTypePm4x10, SOC_TH3_PM4X10_COUNT}, 130 #endif 131 #ifdef PORTMOD_PM8X50_SUPPORT 132 {portmodDispatchTypePm8x50, SOC_TH3_PM8X50_COUNT}, 133 #endif 134 }; 135 136 portmod_pm_instances_t th3_4pipe_pm_types[] = { 137 #ifdef PORTMOD_PM4X10_SUPPORT 138 {portmodDispatchTypePm4x10, SOC_TH3_PM4X10_COUNT}, 139 #endif 140 #ifdef PORTMOD_PM8X50_SUPPORT 141 {portmodDispatchTypePm8x50, (SOC_TH3_PM8X50_COUNT)}, 142 #endif 143 }; 144 145 #define SOC_TH3_MAX_PHYS (261) /* (1x4) 4 XLMAC's, (32x8) 256 CDMAC's */ 146 147 #ifdef PORTMOD_PM4X10_SUPPORT 148 static portmod_default_user_access_t *pm4x10_th3_user_acc[SOC_MAX_NUM_DEVICES]; 149 #endif /* PORTMOD_PM4X10_SUPPORT */ 150 151 #ifdef PORTMOD_PM8X50_SUPPORT 152 static portmod_default_user_access_t *pm8x50_th3_user_acc[SOC_MAX_NUM_DEVICES]; 153 #endif /* PORTMOD_PM8X50_SUPPORT */ 154 155 soc_portctrl_functions_t soc_th3_portctrl_func = { 156 soc_th3_portctrl_pm_portmod_init, 157 soc_th3_portctrl_pm_portmod_deinit, 158 soc_th3_portctrl_pm_port_config_get, 159 soc_th3_portctrl_pm_port_phyaddr_get, 160 NULL, 161 soc_th3_portctrl_pm_type_get, 162 NULL, 163 NULL, 164 soc_th3_portctrl_pm_vco_store_clear, 165 soc_th3_portctrl_pm_vco_store, 166 soc_th3_portctrl_pm_vco_fetch, 167 soc_th3_portctrl_pm_vco_reconfigure, 168 }; 169 170 #if 0 171 /* Commented out for now. However, these registers still exist in TH3, 172 * so this function may be needed in the future 173 */ 174 STATIC int 175 _soc_th3_portctrl_rescal_calculate(int unit, int *val1, int *val2) 176 { 177 uint32 rval, rescal0, rescal1, rescal2, rescal3; 178 soc_reg_t reg = INVALIDr; 179 soc_field_t field = PONf; 180 181 SOC_IF_ERROR_RETURN(READ_TOP_RESCAL_0_STATUS_0r(unit,&rval)); 182 reg = TOP_RESCAL_0_STATUS_0r; 183 rescal0 = soc_reg_field_get(unit, reg, rval, field); 184 185 SOC_IF_ERROR_RETURN(READ_TOP_RESCAL_1_STATUS_0r(unit,&rval)); 186 reg = TOP_RESCAL_1_STATUS_0r; 187 rescal1 = soc_reg_field_get(unit, reg, rval, field); 188 189 SOC_IF_ERROR_RETURN(READ_TOP_RESCAL_2_STATUS_0r(unit,&rval)); 190 reg = TOP_RESCAL_2_STATUS_0r; 191 rescal2 = soc_reg_field_get(unit, reg, rval, field); 192 193 SOC_IF_ERROR_RETURN(READ_TOP_RESCAL_3_STATUS_0r(unit,&rval)); 194 reg = TOP_RESCAL_3_STATUS_0r; 195 rescal3 = soc_reg_field_get(unit, reg, rval, field); 196 197 *val1 = (rescal0 + rescal1) / 2; 198 *val2 = (rescal2 + rescal3) / 2; 199 200 return SOC_E_NONE; 201 } 202 #endif 203 204 STATIC int 205 _soc_th3_portctrl_pm_init(int unit, int *max_phys, 206 portmod_pm_instances_t **pm_types, 207 int *pms_arr_len) 208 { 209 *max_phys = SOC_TH3_MAX_PHYS; 210 if (NUM_PIPE(unit) == 4) { 211 *pm_types = th3_4pipe_pm_types; 212 *pms_arr_len = sizeof(th3_4pipe_pm_types)/sizeof(portmod_pm_instances_t); 213 } else { 214 *pm_types = th3_pm_types; 215 *pms_arr_len = sizeof(th3_pm_types)/sizeof(portmod_pm_instances_t); 216 } 217 return SOC_E_NONE; 218 } 219 220 STATIC int 221 _soc_th3_portctrl_device_addr_port_get(int unit, int pm_type, 222 uint32_t **addr, 223 uint32_t **port, 224 uint32_t **core_num) 225 { 226 *addr = NULL; 227 *port = NULL; 228 *core_num = NULL; 229 if (pm_type == portmodDispatchTypePm4x10) { 230 *addr = _th3_pm4x10_addr; 231 *port = _th3_pm4x10_port; 232 *core_num = _th3_pm4x10_core_num; 233 } else if (pm_type == portmodDispatchTypePm8x50){ 234 *addr = _th3_pm8x50_addr; 235 *port = _th3_pm8x50_port; 236 *core_num = _th3_pm8x50_core_num; 237 } 238 return SOC_E_NONE; 239 } 240 241 STATIC int 242 _soc_th3_portctrl_pm_user_acc_flag_set(int unit, 243 portmod_default_user_access_t* pm_user_access) 244 { 245 PORTMOD_USER_ACCESS_FW_LOAD_REVERSE_SET((pm_user_access)); 246 PORTMOD_USER_ACCESS_REG_VAL_OFFSET_ZERO_CLR((pm_user_access)); 247 return SOC_E_NONE; 248 } 249 250 /* 251 * Polarity get looks for physical port based config. 252 */ 253 STATIC void 254 _soc_th3_portctrl_pm_port_polarity_get(int unit, int logical_port, int physical_port, 255 int lane, uint32 *tx_pol, uint32* rx_pol) 256 { 257 uint32 rx_polarity, tx_polarity; 258 259 rx_polarity = soc_property_phy_get(unit, physical_port, 0, 0, lane, 260 spn_PHY_CHAIN_RX_POLARITY_FLIP_PHYSICAL, 0x0); 261 *rx_pol = (rx_polarity & 0x1) << lane; 262 263 tx_polarity = soc_property_phy_get(unit, physical_port, 0, 0, lane, 264 spn_PHY_CHAIN_TX_POLARITY_FLIP_PHYSICAL, 0x0); 265 *tx_pol = (tx_polarity & 0x1) << lane; 266 } 267 268 STATIC void 269 _soc_th3_portctrl_pm_polarity_get(int unit, int physical_port, 270 uint32 *tx_pol, uint32* rx_pol) 271 { 272 *rx_pol = soc_property_phys_port_get(unit, physical_port, 273 spn_SERDES_CORE_RX_POLARITY_FLIP_PHYSICAL, 0); 274 *tx_pol = soc_property_phys_port_get(unit, physical_port, 275 spn_SERDES_CORE_TX_POLARITY_FLIP_PHYSICAL, 0); 276 } 277 278 279 /* 280 * lanemap get looks for physical port based config. 281 */ 282 STATIC 283 void _soc_th3_portctrl_pm_port_lanemap_get 284 (int unit, int logical_port, int physical_port, int core_num, 285 uint32 *txlane_map, uint32* rxlane_map) 286 { 287 /* If this is the management port PM, this is a 4x10, so the lane mapping 288 * will be different than the 8x50 */ 289 if (core_num == 32) { 290 *rxlane_map = soc_property_phy_get(unit, physical_port, 0, 0, 0, 291 spn_PHY_CHAIN_RX_LANE_MAP_PHYSICAL, 0x3210); 292 293 294 *txlane_map = soc_property_phy_get(unit, physical_port, 0, 0, 0, 295 spn_PHY_CHAIN_TX_LANE_MAP_PHYSICAL, 0x3210); 296 } else { 297 *rxlane_map = soc_property_phy_get(unit, physical_port, 0, 0, 0, 298 spn_PHY_CHAIN_RX_LANE_MAP_PHYSICAL, 0x76543210); 299 300 301 *txlane_map = soc_property_phy_get(unit, physical_port, 0, 0, 0, 302 spn_PHY_CHAIN_TX_LANE_MAP_PHYSICAL, 0x76543210); 303 } 304 } 305 306 307 #define NRZ_MAX_SPEED_PER_LANE 28125 308 STATIC 309 int _soc_th3_portctrl_port_serdes_tx_taps_get 310 (int unit, int logical_port, int *tx_params_user_flag, 311 phymod_tx_t *tx_params) 312 { 313 char *config_str, *sub_str, *sub_str_end; 314 char str_buf[8]; 315 int16_t *field = NULL; 316 static const char nrz[] = "nrz"; 317 static const char pam4[] = "pam4"; 318 soc_info_t *si = &SOC_INFO(unit); 319 int i, temp, speed_per_lane, rv = SOC_E_NONE; 320 321 config_str = soc_property_port_get_str(unit, logical_port, spn_SERDES_TX_TAPS); 322 323 /* If this config is not specified, then SDK will use its own default tx taps val */ 324 if (NULL == config_str) { 325 *tx_params_user_flag = 0; 326 return rv; 327 } 328 329 /* User defined serdes_tx_taps */ 330 *tx_params_user_flag = 1; 331 332 sub_str = config_str; 333 334 /** Parse signalling mode **/ 335 /* Copy over nrz or pam4 */ 336 for (i = 0; i < sizeof(pam4); i++) { 337 if (sub_str[i] == ':' || sub_str[i] == '\0') { 338 break; 339 } 340 str_buf[i] = sub_str[i]; 341 } 342 str_buf[i] = '\0'; 343 344 /* If pam4 */ 345 if (!sal_strcmp(str_buf, pam4)) { 346 tx_params->sig_method = phymodSignallingMethodPAM4; 347 } else if (!sal_strcmp(str_buf, nrz)) { 348 /* nrz */ 349 tx_params->sig_method = phymodSignallingMethodNRZ; 350 } else { 351 LOG_CLI((BSL_META_U(unit, 352 "SERDES_TX_TAPS: Missing signalling mode: %s\n"), 353 str_buf)); 354 rv = SOC_E_CONFIG; 355 goto end; 356 } 357 358 /* Compare signalling mode against speed and # of lanes. 359 * NRZ must be less than 28125 per lane. 360 * PAM4 must be greater than or equal to 50000 per lane. 361 */ 362 /* following tx taps check only applies to init, after init, 363 * this check will be bypassed */ 364 if (!(SOC_CONTROL(unit)->soc_flags & SOC_F_ALL_MODULES_INITED)) { 365 speed_per_lane = si->port_speed_max[logical_port] / 366 si->port_num_lanes[logical_port]; 367 if ((speed_per_lane > NRZ_MAX_SPEED_PER_LANE && 368 tx_params->sig_method == phymodSignallingMethodNRZ) || 369 (speed_per_lane < NRZ_MAX_SPEED_PER_LANE && 370 tx_params->sig_method == phymodSignallingMethodPAM4)) { 371 LOG_CLI((BSL_META_U(unit, 372 "SERDES_TX_TAPS: Port %d speed per lane %d " 373 "not supported for signalling mode %s\n"), 374 logical_port, speed_per_lane, str_buf)); 375 rv = SOC_E_CONFIG; 376 goto end; 377 } 378 } 379 380 /* Set the sub_str to after the signalling type */ 381 sub_str = &sub_str[i]; 382 383 /* Start off at 3 tap mode. If it goes to 6, set that later */ 384 tx_params->tap_mode = phymodTxTapMode3Tap; 385 386 /* Parse each of the different fields after the signalling type */ 387 for (i = 0; i < 6; i++) { 388 /* Set the field to fetch */ 389 switch(i) { 390 case 0: 391 field = &tx_params->pre; 392 break; 393 case 1: 394 field = &tx_params->main; 395 break; 396 case 2: 397 field = &tx_params->post; 398 break; 399 case 3: 400 field = &tx_params->pre2; 401 break; 402 case 4: 403 field = &tx_params->post2; 404 break; 405 case 5: 406 field = &tx_params->post3; 407 tx_params->tap_mode = phymodTxTapMode6Tap; 408 break; 409 default: 410 /* Shouldn't reach this */ 411 break; 412 } 413 414 if (*sub_str != '\0') { 415 if (*sub_str != ':') { 416 LOG_CLI((BSL_META_U(unit, 417 "Port %d: Bad tx taps string\"%s\"\n"), 418 logical_port, config_str)); 419 rv = SOC_E_CONFIG; 420 goto end; 421 } 422 sub_str++; 423 } else { 424 /* Only 3 taps is fine; go to the end */ 425 if (i == 3) { 426 goto end; 427 } 428 429 LOG_CLI((BSL_META_U(unit, 430 "SERDES_TX_TAPS port %d: tx taps string missing a field\"%s\"\n"), 431 logical_port, config_str)); 432 rv = SOC_E_CONFIG; 433 goto end; 434 } 435 436 /* fetch field */ 437 temp = sal_ctoi(sub_str, &sub_str_end); 438 *field = (int16_t)temp; 439 440 if (sub_str == sub_str_end) { 441 LOG_CLI((BSL_META_U(unit, 442 "SERDES_TX_TAPS port %d: tx taps string missing a field\"%s\"\n"), 443 logical_port, config_str)); 444 rv = SOC_E_CONFIG; 445 goto end; 446 } 447 448 sub_str = sub_str_end; 449 } 450 451 end: 452 453 return rv; 454 } 455 #undef NRZ_MAX_SPEED_PER_LANE 456 457 STATIC int 458 _soc_th3_portctrl_pm4x10_portmod_init(int unit, int num_of_instances) 459 { 460 #ifdef PORTMOD_PM4X10_SUPPORT 461 int rv = SOC_E_NONE; 462 portmod_pm_create_info_t pm_info; 463 int pmid = 0, blk, is_sim, found; 464 int first_port, idx, core_num, core_cnt; 465 int port_num_lanes = 0; 466 uint32 *pAddr, *pPort, *pCoreNum; 467 soc_info_t *si; 468 469 si = &SOC_INFO(unit); 470 471 SOC_IF_ERROR_RETURN 472 (_soc_th3_portctrl_device_addr_port_get(unit, 473 portmodDispatchTypePm4x10, 474 &pAddr, &pPort, &pCoreNum)); 475 if (!pAddr || !pPort) { 476 return SOC_E_INTERNAL; 477 } 478 479 /* Allocate PMs */ 480 SOC_IF_ERROR_RETURN 481 (soc_esw_portctrl_pm_user_access_alloc(unit, 482 num_of_instances, 483 &pm4x10_th3_user_acc[unit])); 484 485 for (pmid = 0; PORTMOD_SUCCESS(rv) && (pmid < num_of_instances); pmid++) { 486 487 rv = portmod_pm_create_info_t_init(unit, &pm_info); 488 if (PORTMOD_FAILURE(rv)) { 489 break; 490 } 491 /* PM info */ 492 first_port = pPort[pmid]; 493 494 /* Only two physical ports are used in management pm4x10, 257, 258. 495 * However, each management port can use multiple phy lanes in PM. 496 * As a result, we need to initialize multiple phy lanes in Portmod. */ 497 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port); 498 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+1); 499 500 /* Even though we see physical ports 257 and 258 as the management, 501 * it's actually more like 257 and 259 in port macro. 502 */ 503 if (NUM_PIPE(unit) == 8) { 504 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+2); 505 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+3); 506 } 507 508 /* Check if mgmt ports is configured as 4 lanes */ 509 if (si->port_l2p_mapping[38] != -1) { 510 port_num_lanes = si->port_num_lanes[38]; 511 if (port_num_lanes == 4) { 512 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+2); 513 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+3); 514 } 515 } 516 517 found = 0; 518 for(idx = 0; idx < SOC_DRIVER(unit)->port_num_blktype; idx++){ 519 blk = SOC_PORT_IDX_INFO(unit, first_port, idx).blk; 520 if (SOC_BLOCK_INFO(unit, blk).type == SOC_BLK_XLPORT){ 521 found = 1; 522 break; 523 } 524 } 525 526 if (!found) { 527 rv = SOC_E_INTERNAL; 528 break; 529 } 530 531 pm_info.type = portmodDispatchTypePm4x10; 532 533 /* Init user_acc for phymod access struct */ 534 rv = portmod_default_user_access_t_init(unit, 535 &(pm4x10_th3_user_acc[unit][pmid])); 536 if (PORTMOD_FAILURE(rv)) { 537 break; 538 } 539 540 SOC_IF_ERROR_RETURN( 541 _soc_th3_portctrl_pm_user_acc_flag_set(unit, 542 &(pm4x10_th3_user_acc[unit][pmid]))); 543 544 pm4x10_th3_user_acc[unit][pmid].unit = unit; 545 pm4x10_th3_user_acc[unit][pmid].blk_id = blk; 546 pm4x10_th3_user_acc[unit][pmid].mutex = sal_mutex_create("core mutex"); 547 if (pm4x10_th3_user_acc[unit][pmid].mutex == NULL) { 548 rv = SOC_E_MEMORY; 549 break; 550 } 551 552 /* Specific info for PM4x10 */ 553 rv = phymod_access_t_init(&pm_info.pm_specific_info.pm4x10.access); 554 if (PORTMOD_FAILURE(rv)) { 555 break; 556 } 557 558 pm_info.pm_specific_info.pm4x10.access.user_acc = 559 &(pm4x10_th3_user_acc[unit][pmid]); 560 pm_info.pm_specific_info.pm4x10.access.addr = pAddr[pmid]; 561 pm_info.pm_specific_info.pm4x10.access.bus = NULL; /* Use default bus */ 562 563 rv = soc_physim_check_sim(unit, phymodDispatchTypeTsce16, 564 &(pm_info.pm_specific_info.pm4x10.access), 565 0, &is_sim); 566 if (PORTMOD_FAILURE(rv)) { 567 break; 568 } 569 570 if (is_sim) { 571 /* Firmward loader : Don't allow FW load on sim enviroment */ 572 pm_info.pm_specific_info.pm4x10.fw_load_method = 573 phymodFirmwareLoadMethodNone; 574 /* TSCE sim supports CL45 mode to read/write registers. */ 575 PHYMOD_ACC_F_CLAUSE45_SET(&pm_info.pm_specific_info.pm4x10.access); 576 } 577 578 /* Use default external loader if NULL */ 579 pm_info.pm_specific_info.pm4x10.external_fw_loader = NULL; 580 581 core_cnt = 1; 582 583 for (core_num = 0; core_num < core_cnt; core_num++) { 584 pm_info.pm_specific_info.pm4x10.core_num = pCoreNum? pCoreNum[pmid] : pmid; 585 pm_info.pm_specific_info.pm4x10.core_num_int = 0; 586 pm_info.pm_specific_info.pm4x10.rescal = -1; 587 } 588 589 pm_info.pm_specific_info.pm4x10.portmod_phy_external_reset 590 = soc_esw_portctrl_reset_tsc3_cb; 591 592 /* 4x10 is only used in mgmt ports */ 593 pm_info.pm_specific_info.pm4x10.port_mode_aux_info = portmodModeInfoTwoDualModePorts; 594 595 /* Add PM to PortMod */ 596 rv = portmod_port_macro_add(unit, &pm_info); 597 } 598 599 if (PORTMOD_FAILURE(rv)) { 600 for (pmid = 0; pmid < num_of_instances; pmid++) { 601 if (pm4x10_th3_user_acc[unit][pmid].mutex) { 602 sal_mutex_destroy(pm4x10_th3_user_acc[unit][pmid].mutex); 603 pm4x10_th3_user_acc[unit][pmid].mutex = NULL; 604 } 605 } 606 } 607 608 return rv; 609 #else /* PORTMOD_PM4X10_SUPPORT */ 610 return SOC_E_UNAVAIL; 611 #endif /* PORTMOD_PM4X10_SUPPORT */ 612 } 613 614 /* 615 * Function: 616 * soc_th3_portctrl_ep_rst_egr_enable_cb 617 * Purpose: 618 * Callback function from portmod to perform EP Soft Reset for the port 619 * and to write EGR_ENABLE. 620 * 621 * NOTE: This is ONLY for SW 400G Autoneg! 622 * 623 * Parameters: 624 * unit - (IN) Unit number. 625 * port - (IN) Logical Port 626 * Returns: 627 * SOC_E_XXX 628 */ 629 STATIC int 630 soc_th3_portctrl_ep_rst_egr_enable_cb(int unit, int port) 631 { 632 int phy_port; 633 634 phy_port = SOC_INFO(unit).port_l2p_mapping[port]; 635 636 SOC_IF_ERROR_RETURN(soc_tomahawk3_ep_credit_rst_port(unit, phy_port)); 637 638 return SOC_E_NONE; 639 } 640 641 STATIC int 642 _soc_th3_portctrl_pm8x50_portmod_init(int unit, int num_of_instances) 643 { 644 #ifdef PORTMOD_PM8X50_SUPPORT 645 int rv = SOC_E_NONE; 646 portmod_pm_create_info_t pm_info; 647 int pmid = 0, blk, is_sim, found; 648 int first_port, idx, core_num, core_cnt; 649 uint32 *pAddr, *pPort,*pCoreNum; 650 uint16 dev_id; 651 uint8 rev_id; 652 653 SOC_IF_ERROR_RETURN 654 (_soc_th3_portctrl_device_addr_port_get(unit, 655 portmodDispatchTypePm8x50, 656 &pAddr, &pPort,&pCoreNum)); 657 if (!pAddr || !pPort) { 658 return SOC_E_INTERNAL; 659 } 660 661 /* Allocate PMs */ 662 SOC_IF_ERROR_RETURN 663 (soc_esw_portctrl_pm_user_access_alloc(unit, 664 num_of_instances, 665 &pm8x50_th3_user_acc[unit])); 666 667 soc_cm_get_id(unit, &dev_id, &rev_id); 668 669 for (pmid = 0; PORTMOD_SUCCESS(rv) && (pmid < num_of_instances); pmid++) { 670 671 rv = portmod_pm_create_info_t_init(unit, &pm_info); 672 if (PORTMOD_FAILURE(rv)) { 673 break; 674 } 675 /* PM info */ 676 first_port = pPort[pmid]; 677 678 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port); 679 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+1); 680 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+2); 681 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+3); 682 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+4); 683 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+5); 684 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+6); 685 PORTMOD_PBMP_PORT_ADD(pm_info.phys, first_port+7); 686 687 found = 0; 688 for(idx = 0; idx < SOC_DRIVER(unit)->port_num_blktype; idx++){ 689 blk = SOC_PORT_IDX_INFO(unit, first_port, idx).blk; 690 if (SOC_BLOCK_INFO(unit, blk).type == SOC_BLK_CDPORT){ 691 found = 1; 692 break; 693 } 694 } 695 696 if (!found) { 697 rv = SOC_E_INTERNAL; 698 break; 699 } 700 701 pm_info.type = portmodDispatchTypePm8x50; 702 703 /* Init user_acc for phymod access struct */ 704 rv = portmod_default_user_access_t_init(unit, 705 &(pm8x50_th3_user_acc[unit][pmid])); 706 if (PORTMOD_FAILURE(rv)) { 707 break; 708 } 709 710 PORTMOD_USER_ACCESS_FW_LOAD_REVERSE_SET((&(pm8x50_th3_user_acc[unit][pmid]))); 711 PORTMOD_USER_ACCESS_REG_VAL_OFFSET_ZERO_CLR((&(pm8x50_th3_user_acc[unit][pmid]))); 712 pm8x50_th3_user_acc[unit][pmid].unit = unit; 713 pm8x50_th3_user_acc[unit][pmid].blk_id = blk; 714 pm8x50_th3_user_acc[unit][pmid].mutex = sal_mutex_create("core mutex"); 715 if (pm8x50_th3_user_acc[unit][pmid].mutex == NULL) { 716 rv = SOC_E_MEMORY; 717 break; 718 } 719 720 /* Specific info for PM8x50 */ 721 rv = phymod_phy_access_t_init(&pm_info.pm_specific_info.pm8x50.access); 722 if (PORTMOD_FAILURE(rv)) { 723 break; 724 } 725 726 pm_info.pm_specific_info.pm8x50.access.access.user_acc = 727 &(pm8x50_th3_user_acc[unit][pmid]); 728 pm_info.pm_specific_info.pm8x50.access.access.addr = pAddr[pmid]; 729 /* Use default bus */ 730 pm_info.pm_specific_info.pm8x50.access.access.bus = NULL; 731 /* Use PLL1 as TVCO source */ 732 pm_info.pm_specific_info.pm8x50.access.access.tvco_pll_index = 1; 733 734 rv = soc_physim_check_sim(unit, phymodDispatchTypeTscbh, 735 &(pm_info.pm_specific_info.pm8x50.access.access), 736 0, &is_sim); 737 738 if (PORTMOD_FAILURE(rv)) { 739 break; 740 } 741 742 if (is_sim) { 743 /* Firmward loader : Don't allow FW load on sim enviroment */ 744 pm_info.pm_specific_info.pm8x50.fw_load_method = 745 phymodFirmwareLoadMethodNone; 746 /* TSCF sim supports CL45 mode to read/write registers. */ 747 PHYMOD_ACC_F_CLAUSE45_SET( 748 &pm_info.pm_specific_info.pm8x50.access.access); 749 PHYMOD_ACC_F_PHYSIM_SET( 750 &pm_info.pm_specific_info.pm8x50.access.access); 751 } 752 753 /* Use default external loader if NULL */ 754 pm_info.pm_specific_info.pm8x50.external_fw_loader = NULL; 755 756 core_cnt = 1; 757 758 for (core_num = 0; core_num < core_cnt; core_num++) { 759 pm_info.pm_specific_info.pm8x50.core_num = pCoreNum? pCoreNum[pmid] : pmid; 760 } 761 762 /* Set the TVCO and OVCO for the Port Macro */ 763 pm_info.pm_specific_info.pm8x50.tvco = SOC_INFO(unit).pm_vco_info[pmid].tvco; 764 pm_info.pm_specific_info.pm8x50.ovco = SOC_INFO(unit).pm_vco_info[pmid].ovco; 765 766 767 /* Tell Portmod which Port Macros are the Master Port Macros, meaning 768 * they drive the clock for the slave port macros. */ 769 if (rev_id == BCM56980_A0_REV_ID) { 770 /* In TH3 A0, the "inner" port macros on a pipe are the Masters. 771 * PM 0 is driven by PM 1 and PM 3 is driven by PM 2. 772 */ 773 if (pmid == 1 || pmid == 2 || pmid == 5 || pmid == 6 || pmid == 9 || 774 pmid == 10 || pmid == 13 || pmid == 14 || pmid == 17 || pmid == 18 || 775 pmid == 21 || pmid == 22 || pmid == 25 || pmid == 26 || pmid == 29 || 776 pmid == 30) { 777 pm_info.pm_specific_info.pm8x50.is_master_pm = 1; 778 } else { 779 pm_info.pm_specific_info.pm8x50.is_master_pm = 0; 780 } 781 } else { 782 /* In TH3 B0, there is only 1 master PM per pipe */ 783 if (pmid == 3 || pmid == 4 || pmid == 11 || pmid == 12 || 784 pmid == 19 || pmid == 20 || pmid == 27 || pmid == 28) { 785 pm_info.pm_specific_info.pm8x50.is_master_pm = 1; 786 } else { 787 pm_info.pm_specific_info.pm8x50.is_master_pm = 0; 788 } 789 } 790 791 /* Add callback function for portmod to reset EP and enable 792 * port in 400G AN */ 793 pm_info.pm_specific_info.pm8x50.portmod_egress_buffer_reset = 794 soc_th3_portctrl_ep_rst_egr_enable_cb; 795 796 /* Add PM to PortMod */ 797 rv = portmod_port_macro_add(unit, &pm_info); 798 } 799 800 if (PORTMOD_FAILURE(rv)) { 801 for (pmid = 0; pmid < num_of_instances; pmid++) { 802 if (pm8x50_th3_user_acc[unit][pmid].mutex) { 803 sal_mutex_destroy(pm8x50_th3_user_acc[unit][pmid].mutex); 804 pm8x50_th3_user_acc[unit][pmid].mutex = NULL; 805 } 806 } 807 } 808 809 return rv; 810 #else /* PORTMOD_PM8X50_SUPPORT */ 811 return SOC_E_UNAVAIL; 812 #endif /* PORTMOD_PM8X50_SUPPORT */ 813 return 0; 814 } 815 816 /* 817 * Function: 818 * soc_th3_portctrl_pm_portmod_init 819 * Purpose: 820 * Initialize PortMod and PortMacro for Tomahawk3 821 * Add port macros (PM) to the unit's PortMod Manager (PMM). 822 * Parameters: 823 * unit - (IN) Unit number. 824 * Returns: 825 * SOC_E_XXX 826 */ 827 int 828 soc_th3_portctrl_pm_portmod_init(int unit) 829 { 830 int rv = SOC_E_NONE, pms_arr_len = 0, count, max_phys= 0; 831 portmod_pm_instances_t *pm_types = NULL; 832 int flags = 0; 833 834 /* Call PortMod library initialization */ 835 SOC_IF_ERROR_RETURN( 836 _soc_th3_portctrl_pm_init(unit, &max_phys, 837 &pm_types, &pms_arr_len)); 838 if (pms_arr_len == 0) { 839 return SOC_E_UNAVAIL; 840 } 841 842 /* 843 * If portmod was create - destroy and create again 844 * Better way would be to create once and leave it. 845 */ 846 if (SOC_E_NONE == soc_esw_portctrl_init_check(unit)) { 847 SOC_IF_ERROR_RETURN(portmod_destroy(unit)); 848 } 849 850 PORTMOD_CREATE_F_PM_NULL_SET(flags); 851 852 SOC_IF_ERROR_RETURN 853 (portmod_create(unit, flags, SOC_MAX_NUM_PORTS, max_phys, 854 pms_arr_len, pm_types)); 855 856 for (count = 0; SOC_SUCCESS(rv) && (count < pms_arr_len); count++) { 857 #ifdef PORTMOD_PM4X10_SUPPORT 858 if (pm_types[count].type == portmodDispatchTypePm4x10) { 859 rv = _soc_th3_portctrl_pm4x10_portmod_init 860 (unit, pm_types[count].instances); 861 } else 862 #endif /* PORTMOD_PM4X10_SUPPORT */ 863 #ifdef PORTMOD_PM8X50_SUPPORT 864 if (pm_types[count].type == portmodDispatchTypePm8x50) { 865 rv = _soc_th3_portctrl_pm8x50_portmod_init 866 (unit, pm_types[count].instances); 867 } else 868 #endif /* PORTMOD_PM8X50_SUPPORT */ 869 { 870 rv = SOC_E_INTERNAL; 871 } 872 } 873 874 return rv; 875 } 876 877 /* 878 * Function: 879 * soc_th3_portctrl_pm_portmod_deinit 880 * Purpose: 881 * Deinitialize PortMod and PortMacro for Tomahawk3. 882 * Free pm user access data. 883 * Parameters: 884 * unit - (IN) Unit number. 885 * Returns: 886 * SOC_E_NONE 887 */ 888 int 889 soc_th3_portctrl_pm_portmod_deinit(int unit) 890 { 891 if (SOC_E_INIT == soc_esw_portctrl_init_check(unit)) { 892 return SOC_E_NONE; 893 } 894 895 /* Free PMs structures */ 896 #ifdef PORTMOD_PM4X10_SUPPORT 897 if (pm4x10_th3_user_acc[unit] != NULL) { 898 sal_free(pm4x10_th3_user_acc[unit]); 899 pm4x10_th3_user_acc[unit] = NULL; 900 } 901 #endif /* PORTMOD_PM4X10_SUPPORT */ 902 903 #ifdef PORTMOD_PM8X50_SUPPORT 904 if (pm8x50_th3_user_acc[unit] != NULL) { 905 sal_free(pm8x50_th3_user_acc[unit]); 906 pm8x50_th3_user_acc[unit] = NULL; 907 } 908 #endif /* PORTMOD_PM8X50_SUPPORT */ 909 910 SOC_IF_ERROR_RETURN(portmod_destroy(unit)); 911 912 return SOC_E_NONE; 913 } 914 915 int 916 soc_th3_portctrl_pm_port_config_get(int unit, soc_port_t port, void *port_config) 917 { 918 #if defined (PORTMOD_PM4X10_SUPPORT) || defined(PORTMOD_PM8X50_SUPPORT) 919 int rv = SOC_E_NONE; 920 int pmid = 0, lane, phy, phy_port, logical_port; 921 int first_port, core_num, core_count = 0, core_index, is_sim; 922 int type = portmodDispatchTypeCount; 923 uint32 txlane_map, rxlane_map, i; 924 uint32 *pAddr = NULL, *pPort = NULL, *pCoreNum = NULL; 925 uint32 tx_polarity, rx_polarity; 926 portmod_port_init_config_t *port_config_info; 927 phymod_firmware_load_method_t fw_load_method; 928 phymod_polarity_t polarity; /**< Lanes Polarity */ 929 phymod_lane_map_t lane_map; 930 portmod_dispatch_type_t pm_type = portmodDispatchTypeCount; 931 int num_lanes = 0; 932 933 port_config_info = (portmod_port_init_config_t *)port_config; 934 935 phy = SOC_INFO(unit).port_l2p_mapping[port]; 936 /* Tomahawk 3's Management Port Macro requires a spacing between 937 * the lanes, so even though the two management ports' physical 938 * ports are 257 and 258, the lane needs to be the next one, 939 * so logical port 118 being mapped to physical port 258 needs 940 * to pass 259 to portmod because portmod only recognizes lane 941 * 0 (physical port 257) and lane 2 (physial port 259). 942 */ 943 if (phy == 258) { 944 phy = 259; 945 } 946 947 rv = portmod_phy_pm_type_get(unit, phy, &pm_type); 948 if (rv < 0) { 949 return rv; 950 } 951 952 core_num = -1; 953 954 switch (pm_type) { 955 case portmodDispatchTypePm4x10: 956 num_lanes = SOC_PM4X10_NUM_LANES; 957 core_num = 32; 958 break; 959 case portmodDispatchTypePm8x50: 960 num_lanes = 8; 961 core_num = (phy - 1)/num_lanes ; 962 break; 963 default: 964 return SOC_E_INTERNAL; 965 break; 966 } 967 968 /* Find the port belong to which PM. The port has its own core id, using it to compare PM. */ 969 for (i=0; i<SOC_TH3_PM4X10_COUNT; i++) { 970 if (core_num == _th3_pm4x10_core_num[i]) { 971 type = portmodDispatchTypePm4x10; 972 SOC_IF_ERROR_RETURN 973 (_soc_th3_portctrl_device_addr_port_get(unit, 974 portmodDispatchTypePm4x10, 975 &pAddr, &pPort, &pCoreNum)); 976 pmid = i; 977 core_count = 1; 978 break; 979 } 980 } 981 /* When port dones't find PM4x10, find PM8x50 again. */ 982 if (i == SOC_TH3_PM4X10_COUNT) { 983 for (i=0; i<SOC_TH3_PM8X50_COUNT; i++) { 984 if (core_num == _th3_pm8x50_core_num[i]) { 985 type = portmodDispatchTypePm8x50; 986 SOC_IF_ERROR_RETURN 987 (_soc_th3_portctrl_device_addr_port_get(unit, 988 portmodDispatchTypePm8x50, 989 &pAddr, &pPort, &pCoreNum)); 990 pmid = i; 991 core_count = 1; 992 break; 993 } 994 } 995 } 996 997 if (!pAddr || !pPort) { 998 return SOC_E_INTERNAL; 999 } 1000 1001 /* Parse TX TAPS info from config file for the port */ 1002 SOC_IF_ERROR_RETURN(_soc_th3_portctrl_port_serdes_tx_taps_get 1003 (unit, port, 1004 &port_config_info->tx_params_user_flag[0], 1005 &port_config_info->tx_params[0])); 1006 /* Copy the above into each lane for the port */ 1007 for (i = 1; i < SOC_INFO(unit).port_num_lanes[port]; i++) { 1008 port_config_info->tx_params_user_flag[i] = 1009 port_config_info->tx_params_user_flag[0]; 1010 1011 port_config_info->tx_params[i].sig_method = 1012 port_config_info->tx_params[0].sig_method; 1013 1014 port_config_info->tx_params[i].tap_mode = 1015 port_config_info->tx_params[0].tap_mode; 1016 1017 port_config_info->tx_params[i].pre = 1018 port_config_info->tx_params[0].pre; 1019 1020 port_config_info->tx_params[i].main = 1021 port_config_info->tx_params[0].main; 1022 1023 port_config_info->tx_params[i].post = 1024 port_config_info->tx_params[0].post; 1025 1026 port_config_info->tx_params[i].pre2 = 1027 port_config_info->tx_params[0].pre2; 1028 1029 port_config_info->tx_params[i].post2 = 1030 port_config_info->tx_params[0].post2; 1031 1032 port_config_info->tx_params[i].post3 = 1033 port_config_info->tx_params[0].post3; 1034 } 1035 1036 1037 /* PM info */ 1038 first_port = pPort[pmid]; 1039 1040 for (core_index = 0; core_index < core_count; core_index++) { 1041 fw_load_method = phymodFirmwareLoadMethodExternal; 1042 1043 soc_physim_enable_get(unit, &is_sim); 1044 1045 if (is_sim) { 1046 /* Firmward loader : Don't allow FW load on sim enviroment */ 1047 fw_load_method = phymodFirmwareLoadMethodNone; 1048 } else { 1049 fw_load_method = soc_property_suffix_num_get(unit, pmid, 1050 spn_LOAD_FIRMWARE, "quad", 1051 phymodFirmwareLoadMethodExternal); 1052 fw_load_method &= 0xff; 1053 } 1054 1055 rv = phymod_polarity_t_init(&polarity); 1056 if (PORTMOD_FAILURE(rv)) { 1057 break; 1058 } 1059 1060 /* The PM8x50 has a per core polarity. 1061 * The phy_port is the first port of the port macro */ 1062 if (type == portmodDispatchTypePm8x50) { 1063 phy_port = first_port; 1064 _soc_th3_portctrl_pm_polarity_get(unit, phy_port, &tx_polarity, &rx_polarity); 1065 polarity.rx_polarity = rx_polarity; 1066 polarity.tx_polarity = tx_polarity; 1067 } else { 1068 /* The PM4x10 has a per lane polarity config */ 1069 for (lane = 0; lane < num_lanes; lane++) { 1070 phy_port = first_port + lane + (core_index*4); 1071 logical_port = SOC_INFO(unit).port_p2l_mapping[phy_port]; 1072 1073 _soc_th3_portctrl_pm_port_polarity_get(unit, logical_port, phy_port, lane, &tx_polarity, &rx_polarity); 1074 1075 polarity.rx_polarity |= rx_polarity; 1076 polarity.tx_polarity |= tx_polarity; 1077 } 1078 } 1079 1080 /* Lane map */ 1081 rv = phymod_lane_map_t_init(&lane_map); 1082 if (PORTMOD_FAILURE(rv)) { 1083 break; 1084 } 1085 1086 phy_port = first_port + (core_index*4); 1087 logical_port = SOC_INFO(unit).port_p2l_mapping[phy_port]; 1088 1089 _soc_th3_portctrl_pm_port_lanemap_get(unit, logical_port, phy_port, core_num, &txlane_map, &rxlane_map); 1090 1091 if (type == portmodDispatchTypePm8x50) { 1092 lane_map.num_of_lanes = SOC_PM8X50_NUM_LANES; 1093 } else { 1094 lane_map.num_of_lanes = SOC_PM4X10_NUM_LANES; 1095 } 1096 1097 #define BITS_PER_LANE 4 1098 #define LANE_BITMASK 0xF 1099 1100 /* For a PM8x50, the default lane will come back as 0x76543210, so 1101 * we're going to store, for example, the number 7 as the 7th lane 1102 * in lane_map_tx[]. So, shift it right by (lane * 4) bits, which is 1103 * 7 * 4 = 28. Then mask those 4 bits to store the 7 into 1104 * lane_map_tx[7]. 1105 * If the 6 was going to be stored, shift right by 6 * 4 bits, mask 1106 * those 4 bits, and store the value into lane_map_tx[6]. 1107 * 1108 * The PM4x10 has a default lane map of 0x3210 */ 1109 for(lane = 0 ; lane < lane_map.num_of_lanes; lane++) { 1110 lane_map.lane_map_tx[lane] = 1111 (txlane_map >> (lane * BITS_PER_LANE)) & 1112 LANE_BITMASK; 1113 lane_map.lane_map_rx[lane] = 1114 (rxlane_map >> (lane * BITS_PER_LANE)) & 1115 LANE_BITMASK; 1116 } 1117 #undef BITS_PER_LANE 1118 #undef LANE_BITMASK 1119 1120 sal_memcpy(&port_config_info->fw_load_method[core_index], &fw_load_method, 1121 sizeof(phymod_firmware_load_method_t)); 1122 port_config_info->fw_load_method_overwrite = 1; 1123 sal_memcpy(&port_config_info->polarity[core_index], &polarity, 1124 sizeof(phymod_polarity_t)); 1125 port_config_info->polarity_overwrite = 1; 1126 sal_memcpy(&port_config_info->lane_map[core_index], &lane_map, 1127 sizeof(phymod_lane_map_t)); 1128 port_config_info->lane_map_overwrite = 1; 1129 } 1130 1131 return rv; 1132 #else /* PORTMOD_PM4X10_SUPPORT */ 1133 return SOC_E_UNAVAIL; 1134 #endif /* PORTMOD_PM4X10_SUPPORT */ 1135 } 1136 1137 int 1138 soc_th3_portctrl_pm_port_phyaddr_get(int unit, soc_port_t port) 1139 { 1140 int phy, core_index; 1141 uint32 i, *pAddr = NULL, *pPort = NULL, *pCoreNum = NULL; 1142 1143 phy = SOC_INFO(unit).port_l2p_mapping[port]; 1144 1145 /* Find the port belong to which PM. The port has its own core id, using it to compare PM. */ 1146 core_index = (phy - 1) / SOC_PM4X10_NUM_LANES; 1147 #ifdef PORTMOD_PM4X10_SUPPORT 1148 for (i=0; i<SOC_TH3_PM4X10_COUNT; i++) { 1149 if (core_index == _th3_pm4x10_core_num[i]) { 1150 SOC_IF_ERROR_RETURN 1151 (_soc_th3_portctrl_device_addr_port_get(unit, 1152 portmodDispatchTypePm4x10, 1153 &pAddr, &pPort, &pCoreNum)); 1154 return pAddr[i]; 1155 } 1156 } 1157 #endif /* PORTMOD_PM4X10_SUPPORT */ 1158 1159 #ifdef PORTMOD_PM8X50_SUPPORT 1160 /* When port dones't find PM4x10, find PM8x50 again. */ 1161 for (i=0; i<SOC_TH3_PM8X50_COUNT; i++) { 1162 if (core_index == _th3_pm8x50_core_num[i]) { 1163 SOC_IF_ERROR_RETURN 1164 (_soc_th3_portctrl_device_addr_port_get(unit, 1165 portmodDispatchTypePm8x50, 1166 &pAddr, &pPort, &pCoreNum)); 1167 return pAddr[i]; 1168 } 1169 } 1170 #endif /* PORTMOD_PM8X50_SUPPORT */ 1171 1172 return -1; 1173 } 1174 1175 int 1176 soc_th3_portctrl_pm_type_get(int unit, soc_port_t phy_port, int* pm_type) 1177 { 1178 int rv; 1179 1180 *pm_type = -1; 1181 1182 if (phy_port >= 1 && phy_port <= 256) { 1183 #ifdef PORTMOD_PM8X50_SUPPORT 1184 *pm_type = portmodDispatchTypePm8x50; 1185 rv = SOC_E_NONE; 1186 #else 1187 rv = SOC_E_UNAVAIL; 1188 #endif 1189 } else if (phy_port == 257 /* _TH3_PHY_PORT_MNG0 */ || 1190 phy_port == 258 /* _TH3_PHY_PORT_MNG1 */ || 1191 phy_port == 259 /* mark 259 as management port because of pm4x10 1192 lane issue */) { 1193 #ifdef PORTMOD_PM4X10_SUPPORT 1194 *pm_type = portmodDispatchTypePm4x10; 1195 rv = SOC_E_NONE; 1196 #else 1197 rv = SOC_E_UNAVAIL; 1198 #endif 1199 } else { 1200 rv = SOC_E_PARAM; 1201 } 1202 1203 return rv; 1204 } 1205 1206 /* 1207 * Function: 1208 * soc_th3_portctrl_pm_vco_reconfigure 1209 * Purpose: 1210 * Reconfigure the VCOs of Port Macros that need to be reconfigured. 1211 * This normally occurs after a flexport operation. For Port Macros that 1212 * have their TVCO changed, the entire port macro needs to be brought down 1213 * and back up, so it is NOT necessary to call pm_vco_reconfig for those 1214 * Port Macros. 1215 * 1216 * Parameters: 1217 * unit - (IN) Unit number. 1218 * Returns: 1219 * SOC_E_XXX 1220 */ 1221 int 1222 soc_th3_portctrl_pm_vco_reconfigure(int unit) 1223 { 1224 int num_vco; 1225 int pm_id, portmod_pm_id; 1226 int base_phy_port, phy_port, logical_port; 1227 int is_init; 1228 portmod_vco_type_t vco[2]; 1229 1230 soc_info_t *si = &SOC_INFO(unit); 1231 1232 /* Iterate through the affected ports in the PM */ 1233 for (pm_id = 0; pm_id < _TH3_PBLKS_PER_DEV; pm_id++) { 1234 base_phy_port = (pm_id * _TH3_PORTS_PER_PBLK) + 1; 1235 1236 logical_port = -1; 1237 1238 for (phy_port = base_phy_port; 1239 phy_port < base_phy_port + _TH3_PORTS_PER_PBLK; 1240 phy_port++) { 1241 logical_port = si->port_p2l_mapping[phy_port]; 1242 if (SOC_PBMP_PORT_VALID(logical_port)) { 1243 break; 1244 } 1245 } 1246 1247 /* no logical port found on this PM. Continue to next */ 1248 if (!SOC_PBMP_PORT_VALID(logical_port)) { 1249 continue; 1250 } 1251 1252 sal_memset(vco, 0, sizeof(vco)); 1253 1254 num_vco = 0; 1255 if ((si->pm_vco_info[pm_id].is_tvco_new == 1) && 1256 (si->pm_vco_info[pm_id].is_ovco_new == 1)) { 1257 /* Reconfigure VCOs only when VCOs in database are newly updated */ 1258 si->pm_vco_info[pm_id].is_tvco_new = 0; 1259 vco[num_vco] = si->pm_vco_info[pm_id].tvco; 1260 num_vco++; 1261 si->pm_vco_info[pm_id].is_ovco_new = 0; 1262 vco[num_vco] = si->pm_vco_info[pm_id].ovco; 1263 num_vco++; 1264 } 1265 1266 /* No New VCOs; skip this PM */ 1267 if (num_vco == 0) { 1268 continue; 1269 } 1270 1271 /* Fetch the portmod pm id since indexing is different than sdk */ 1272 SOC_IF_ERROR_RETURN(portmod_phy_pm_id_get(unit, base_phy_port, 1273 &portmod_pm_id)); 1274 1275 /* Check if the core is initialized. If it's NOT initialized, 1276 * we don't need to call vco reconfigure because initializing 1277 * the core will set the VCOs 1278 */ 1279 SOC_IF_ERROR_RETURN(portmod_pm_is_initialized(unit, portmod_pm_id, &is_init)); 1280 1281 /* If the core isn't initialized, skip this, since core init will 1282 * set VCO 1283 */ 1284 if (!PORTMOD_CORE_INIT_FLAG_INITIALZIED_GET(is_init)) { 1285 continue; 1286 } 1287 1288 LOG_VERBOSE(BSL_LS_SOC_PORT, 1289 (BSL_META_U(unit, 1290 " PM VCO reconfigure " 1291 "PM=%d TVCO=%d OVCO=%d\n"), 1292 pm_id, vco[0], vco[1])); 1293 1294 /* Reconfigure the VCO for this port macro 1295 * and then move onto the other port macros 1296 */ 1297 SOC_IF_ERROR_RETURN(portmod_pm_vco_reconfig(unit, 1298 portmod_pm_id, vco)); 1299 } 1300 1301 return SOC_E_NONE; 1302 } 1303 1304 /* 1305 * Function: 1306 * soc_th3_portctrl_vco_soc_info_update 1307 * Purpose: 1308 * Update the SOC_INFO's VCO information. 1309 * 1310 * NOTE: This is only called at init! 1311 * Parameters: 1312 * unit - (IN) Unit number. 1313 * Returns: 1314 * SOC_E_XXX 1315 */ 1316 int 1317 soc_th3_portctrl_vco_soc_info_update(int unit) 1318 { 1319 int blk_idx; 1320 int phy_port; 1321 int pm_type; 1322 int index; 1323 int port_list[_TH3_PORTS_PER_PBLK]; 1324 uint32 flags = 0; 1325 1326 for (blk_idx = 0; blk_idx < _TH3_PBLKS_PER_DEV; blk_idx++) { 1327 /* clear the port list for each port macro and the index 1328 * so that it can be filled for each port macro */ 1329 memset(port_list, 0, sizeof(port_list)); 1330 index = 0; 1331 pm_type = -1; 1332 for (phy_port = (blk_idx * _TH3_PORTS_PER_PBLK) + 1; 1333 phy_port <= (blk_idx + 1)*_TH3_PORTS_PER_PBLK; 1334 phy_port++) { 1335 1336 /* Set the device specific pm type. This is necessary since 1337 * portmod has NOT been initialized yet, so querying portmod 1338 * what kind of pm type it has WILL NOT work. */ 1339 if (pm_type < 0) { 1340 SOC_IF_ERROR_RETURN(soc_th3_portctrl_pm_type_get(unit, phy_port, 1341 &pm_type)); 1342 } 1343 1344 port_list[index] = phy_port; 1345 index++; 1346 } 1347 1348 /* Set PM version flag for PM8x50 */ 1349 if (pm_type == portmodDispatchTypePm8x50) { 1350 PORTMOD_PM8X50_REV0_16NM_SET(flags); 1351 } 1352 /* Update the tvco and ovco for this port macro so that the info 1353 * can be passed to portmod during portmod init */ 1354 SOC_IF_ERROR_RETURN(soc_esw_portctrl_pm_update_vco_soc_info(unit, 1355 port_list, 1356 _TH3_PORTS_PER_PBLK, 1357 blk_idx, 1358 pm_type, 1359 flags)); 1360 } 1361 1362 return SOC_E_NONE; 1363 } 1364 1365 /* 1366 * Function: 1367 * soc_th3_portctrl_pm_vco_store_clear 1368 * Purpose: 1369 * Clear the calculated VCO from a flexport operation 1370 * 1371 * Parameters: 1372 * unit - (IN) Unit number. 1373 * Returns: 1374 * SOC_E_XXX 1375 */ 1376 int 1377 soc_th3_portctrl_pm_vco_store_clear(int unit) 1378 { 1379 soc_pmvco_info_t vco_info; 1380 int i; 1381 1382 vco_info.tvco = -1; 1383 vco_info.ovco = -1; 1384 vco_info.is_tvco_new = 0; 1385 vco_info.is_ovco_new = 0; 1386 1387 for (i = 0; i < SOC_TH3_PM8X50_COUNT; i++) { 1388 sal_memcpy(&out_pmvco_info[i], &vco_info, sizeof(soc_pmvco_info_t)); 1389 } 1390 1391 return SOC_E_NONE; 1392 } 1393 1394 /* 1395 * Function: 1396 * soc_th3_portctrl_pm_vco_store 1397 * Purpose: 1398 * Store the calculated VCOs from a flexport operation 1399 * 1400 * Parameters: 1401 * unit - (IN) Unit number. 1402 * index - (IN) Port macro index 1403 * pm_vco_info - (IN) VCO info 1404 * Returns: 1405 * SOC_E_XXX 1406 */ 1407 int 1408 soc_th3_portctrl_pm_vco_store(int unit, int index, const void *pm_vco_info) 1409 { 1410 soc_pmvco_info_t *vco_info = (soc_pmvco_info_t *)pm_vco_info; 1411 1412 if (index >= SOC_MAX_NUM_BLKS) { 1413 return SOC_E_PARAM; 1414 } 1415 sal_memcpy(&out_pmvco_info[index], vco_info, sizeof(soc_pmvco_info_t)); 1416 return SOC_E_NONE; 1417 } 1418 1419 /* 1420 * Function: 1421 * soc_th3_portctrl_pm_vco_fetch 1422 * Purpose: 1423 * Fetch the calculated VCOs from a flexport operation 1424 * 1425 * Parameters: 1426 * unit - (IN) Unit number. 1427 * index - (IN) Port Macro index 1428 * pm_vco_info - (OUT) VCO info 1429 * Returns: 1430 * SOC_E_XXX 1431 */ 1432 int 1433 soc_th3_portctrl_pm_vco_fetch(int unit, int index, void *pm_vco_info) 1434 { 1435 if (index >= SOC_MAX_NUM_BLKS) { 1436 return SOC_E_PARAM; 1437 } 1438 1439 if (pm_vco_info == NULL) { 1440 return SOC_E_PARAM; 1441 } 1442 1443 sal_memcpy(pm_vco_info, &out_pmvco_info[index], sizeof(soc_pmvco_info_t)); 1444 1445 return SOC_E_NONE; 1446 } 1447 1448 /* 1449 * Function: 1450 * soc_th3_portctrl_pm_is_active 1451 * Purpose: 1452 * Given a physical port, find out if the PM it is on is active 1453 * 1454 * Parameters: 1455 * unit - (IN) Unit number. 1456 * phy_port - (IN) Physical port 1457 * is_active - (OUT) PM is active or not 1458 * Returns: 1459 * SOC_E_XXX 1460 */ 1461 int soc_th3_portctrl_pm_is_active(int unit, int phy_port, int *is_active) 1462 { 1463 int portmod_pm_id, rv; 1464 1465 /* if Portmod isn't up yet, just say the PM is not active */ 1466 if (SOC_E_NONE != soc_esw_portctrl_init_check(unit)) { 1467 *is_active = 0; 1468 return SOC_E_NONE; 1469 } 1470 1471 if (phy_port < 1 || phy_port > SOC_TH3_PHY_PORTS_PER_DEV) { 1472 return SOC_E_PORT; 1473 } 1474 1475 rv = portmod_phy_pm_id_get(unit, phy_port, &portmod_pm_id); 1476 1477 if (SOC_SUCCESS(rv)) { 1478 rv = portmod_pm_is_initialized(unit, portmod_pm_id, is_active); 1479 } 1480 1481 return rv; 1482 } 1483 #endif /* BCM_TOMAHAWK3_SUPPORT */