openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 */