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 (26259B)


      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 
     10 #include <sal/core/libc.h>
     11 
     12 #include <soc/debug.h>
     13 #include <soc/util.h>
     14 #include <soc/bondoptions.h>
     15 #include <soc/mem.h>
     16 #include <soc/esw/portctrl.h>
     17 #include <shared/bsl.h>
     18 #include <soc/phy/phymod_sim.h>
     19 #include <soc/portmod/portmod.h>
     20 #include <soc/maverick2.h>
     21 
     22 #ifdef BCM_MAVERICK2_SUPPORT
     23 
     24 #define SOC_MV2_PM4X10_COUNT         1
     25 static uint32_t _mv2_pm4x10_addr[SOC_MV2_PM4X10_COUNT] = { 0x1c1 };
     26 
     27 #define SOC_MV2_PM4X25_COUNT  20
     28 #define SOC_MV2_MAX_PHYS      87  /* 20*4 CLMAC's + 4 XLMAC */
     29 
     30 static uint32_t _mv2_pm4x25_addr[SOC_MV2_PM4X25_COUNT] = {
     31     0x81,  0x85,  0x89,  0x8D,  0x91,
     32     0xA1,  0xA5,  0xA9,  0xAD,  0xB1,
     33     0xC1,  0xC5,  0xC9,  0xCD,  0xD1,
     34     0xE1,  0xE5,  0xE9,  0xED,  0xF1,
     35 };
     36 
     37 
     38 static portmod_pm_instances_t mv2_pm_types[] = {
     39 #ifdef PORTMOD_PM4X25_SUPPORT
     40         {portmodDispatchTypePm4x25,  SOC_MV2_PM4X25_COUNT},
     41 #endif
     42 #ifdef PORTMOD_PM4X10_SUPPORT
     43         {portmodDispatchTypePm4x10,  SOC_MV2_PM4X10_COUNT},
     44 #endif
     45 };
     46 
     47 #ifdef PORTMOD_PM4X25_SUPPORT
     48 static portmod_default_user_access_t *pm4x25_mv2_user_acc[SOC_MAX_NUM_DEVICES];
     49 #endif /* PORTMOD_PM4X25_SUPPORT */
     50 
     51 #ifdef PORTMOD_PM4X10_SUPPORT
     52 static portmod_default_user_access_t *pm4x10_mv2_user_acc[SOC_MAX_NUM_DEVICES];
     53 #endif /* PORTMOD_PM4X25_SUPPORT */
     54 
     55 
     56 
     57 /*
     58  * Polarity get looks for physical port based config first. This will enable
     59  * the user to define the polarity for all ports weather mapped to logical 
     60  * port or not.
     61  *
     62  * For legacy compatibility - we still look for the logical port
     63  * config setup.
     64  */
     65 STATIC void
     66 mv2_pm_port_polarity_get (int unit, int logical_port, int physical_port,
     67                           int lane, uint32 *tx_pol, uint32* rx_pol)
     68 {
     69     uint32 rx_polarity, tx_polarity;
     70 
     71     rx_polarity = soc_property_phy_get(unit, physical_port, 0, 0, lane,
     72                          spn_PHY_CHAIN_RX_POLARITY_FLIP_PHYSICAL, 0x0);
     73     *rx_pol = (rx_polarity & 0x1) << lane;
     74 
     75     tx_polarity = soc_property_phy_get(unit, physical_port, 0, 0, lane,
     76                          spn_PHY_CHAIN_TX_POLARITY_FLIP_PHYSICAL, 0x0);
     77     *tx_pol = (tx_polarity & 0x1) << lane;
     78 }
     79 
     80 /*
     81  * lanemap get looks for physical port based config first. This will enable
     82  * the user to define the lanemap for all ports weather mapped to logical 
     83  * port or not.
     84  *
     85  * For legacy compatibility - we still look for the logical port
     86  * config setup.
     87  */
     88 STATIC 
     89 void mv2_pm_port_lanemap_get (int unit, int logical_port, int physical_port, 
     90                            uint32 *txlane_map, uint32* rxlane_map)       
     91 {
     92     *rxlane_map = soc_property_phy_get(unit, physical_port, 0, 0, 0,
     93                         spn_PHY_CHAIN_RX_LANE_MAP_PHYSICAL, 0x3210);
     94 
     95     *txlane_map = soc_property_phy_get(unit, physical_port, 0, 0, 0,
     96                         spn_PHY_CHAIN_TX_LANE_MAP_PHYSICAL, 0x3210);
     97 }
     98 
     99 
    100 STATIC int
    101 _soc_mv2_portctrl_pm4x25_portmod_init(int unit, int second_mgmt_port)
    102 {
    103 #ifdef PORTMOD_PM4X25_SUPPORT
    104     int rv = SOC_E_NONE;
    105     portmod_pm_create_info_t pm_create_info;
    106     int pmid = 0, blk, is_sim, lane, phy, found, logical_port;
    107     int first_port, idx, ref_clk_prop;
    108     uint32 txlane_map, rxlane_map;
    109     uint32 tx_polarity, rx_polarity;
    110 
    111     /* Allocate user access for all PMs */
    112     SOC_IF_ERROR_RETURN (soc_esw_portctrl_pm_user_access_alloc(unit, 
    113                   SOC_MV2_PM4X25_COUNT, &pm4x25_mv2_user_acc[unit]));
    114 
    115 
    116     for (pmid = 0; PORTMOD_SUCCESS(rv) && (pmid < SOC_MV2_PM4X25_COUNT); pmid++) {
    117 
    118         rv = portmod_pm_create_info_t_init(unit, &pm_create_info);
    119         if (PORTMOD_FAILURE(rv)) {
    120             break;
    121         }
    122 
    123         pm_create_info.type         = portmodDispatchTypePm4x25;
    124 
    125         /* 1 based port number */
    126         first_port = 1 + (pmid << 2);
    127 
    128         SOC_PBMP_PORT_ADD(pm_create_info.phys, first_port);
    129         SOC_PBMP_PORT_ADD(pm_create_info.phys, first_port+1);
    130         SOC_PBMP_PORT_ADD(pm_create_info.phys, first_port+2);
    131         SOC_PBMP_PORT_ADD(pm_create_info.phys, first_port+3);
    132 
    133         /* Identify the block for this particular port */
    134         found = 0;
    135 
    136         for(idx = 0; idx < SOC_DRIVER(unit)->port_num_blktype; idx++){
    137             blk = SOC_PORT_IDX_INFO(unit, first_port, idx).blk;
    138             if (SOC_BLOCK_INFO(unit, blk).type ==
    139                 (soc_feature(unit, soc_feature_clport_gen2) ? SOC_BLK_CLG2PORT : SOC_BLK_CLPORT)){
    140                 found = 1;
    141                 break;
    142             }
    143         }
    144 
    145         if (!found) {
    146             rv = SOC_E_INTERNAL;
    147             break;
    148         }
    149 
    150 
    151         /* Init user_acc for phymod access struct */
    152         rv = portmod_default_user_access_t_init(unit,
    153                                                 &(pm4x25_mv2_user_acc[unit][pmid]));
    154         if (PORTMOD_FAILURE(rv)) {
    155             break;
    156         }
    157 
    158         PORTMOD_USER_ACCESS_FW_LOAD_REVERSE_SET((&(pm4x25_mv2_user_acc[unit][pmid])));
    159         pm4x25_mv2_user_acc[unit][pmid].unit = unit;
    160         pm4x25_mv2_user_acc[unit][pmid].blk_id = blk;
    161         pm4x25_mv2_user_acc[unit][pmid].mutex = sal_mutex_create("core mutex");
    162 
    163         if (pm4x25_mv2_user_acc[unit][pmid].mutex == NULL) {
    164             rv = SOC_E_MEMORY;
    165             break;
    166         }
    167 
    168         /* Specific info for PM4x25 */
    169         rv = phymod_access_t_init(&pm_create_info.pm_specific_info.pm4x25.access);
    170         if (PORTMOD_FAILURE(rv)) {
    171             break;
    172         }
    173 
    174         pm_create_info.pm_specific_info.pm4x25.access.user_acc = &(pm4x25_mv2_user_acc[unit][pmid]);
    175         pm_create_info.pm_specific_info.pm4x25.access.addr     = _mv2_pm4x25_addr[pmid];
    176         pm_create_info.pm_specific_info.pm4x25.access.bus      = NULL; /* Use default bus */
    177         pm_create_info.pm_specific_info.pm4x25.rescal          = -1;
    178 
    179         rv = soc_physim_check_sim(unit, phymodDispatchTypeTscf,
    180                                   &(pm_create_info.pm_specific_info.pm4x25.access),
    181                                   0, &is_sim);
    182 
    183         if (PORTMOD_FAILURE(rv)) {
    184             break;
    185         }
    186 
    187         if (is_sim) {
    188             pm_create_info.pm_specific_info.pm4x25.access.bus->bus_capabilities |=
    189                 (PHYMOD_BUS_CAP_WR_MODIFY | PHYMOD_BUS_CAP_LANE_CTRL);
    190 
    191             /* Firmward loader : Don't allow FW load on sim enviroment */
    192             pm_create_info.pm_specific_info.pm4x25.fw_load_method =
    193                 phymodFirmwareLoadMethodNone;
    194         } else {
    195             pm_create_info.pm_specific_info.pm4x25.fw_load_method =
    196                 soc_property_suffix_num_get(unit, pmid,
    197                                             spn_LOAD_FIRMWARE, "quad",
    198                                             phymodFirmwareLoadMethodExternal);
    199             pm_create_info.pm_specific_info.pm4x25.fw_load_method &= 0xff;
    200         }
    201 
    202         /* Use default external loader if NULL */
    203         pm_create_info.pm_specific_info.pm4x25.external_fw_loader = NULL;
    204 
    205         /* Polarity */
    206         rv = phymod_polarity_t_init (&(pm_create_info.pm_specific_info.pm4x25.polarity));
    207         if (PORTMOD_FAILURE(rv)) {
    208             break;
    209         }
    210 
    211         for (lane = 0; lane < SOC_PM4X25_NUM_LANES; lane++) {
    212             phy = first_port+lane;
    213 
    214             logical_port = SOC_INFO(unit).port_p2l_mapping[phy];
    215 
    216             mv2_pm_port_polarity_get (unit, logical_port, phy, lane, &tx_polarity, &rx_polarity);
    217 
    218             pm_create_info.pm_specific_info.pm4x25.polarity.rx_polarity |= rx_polarity;
    219             pm_create_info.pm_specific_info.pm4x25.polarity.tx_polarity |= tx_polarity;
    220         }
    221 
    222         /* Lane map */
    223         rv = phymod_lane_map_t_init
    224             (&(pm_create_info.pm_specific_info.pm4x25.lane_map));
    225         if (PORTMOD_FAILURE(rv)) {
    226             break;
    227         }
    228 
    229         logical_port = SOC_INFO(unit).port_p2l_mapping[first_port];
    230 
    231         mv2_pm_port_lanemap_get (unit, logical_port, first_port, &txlane_map, &rxlane_map);       
    232 
    233         pm_create_info.pm_specific_info.pm4x25.lane_map.num_of_lanes = SOC_PM4X25_NUM_LANES;
    234         pm_create_info.pm_specific_info.pm4x25.core_num = pmid; 
    235         pm_create_info.pm_specific_info.pm4x25.core_num_int = 0;
    236 
    237         for(lane=0 ; lane<SOC_PM4X25_NUM_LANES; lane++) {
    238 
    239             pm_create_info.pm_specific_info.pm4x25.lane_map.lane_map_tx[lane] =
    240                 (txlane_map >> (lane * SOC_PM4X25_NUM_LANES)) &
    241                 SOC_PM4X25_LANE_MASK;
    242 
    243             pm_create_info.pm_specific_info.pm4x25.lane_map.lane_map_rx[lane] =
    244                 (rxlane_map >> (lane * SOC_PM4X25_NUM_LANES)) &
    245                 SOC_PM4X25_LANE_MASK;
    246         }
    247 
    248         ref_clk_prop = soc_property_port_get(unit, first_port,
    249                             spn_XGXS_LCPLL_XTAL_REFCLK, 156);
    250 
    251 
    252         if ((ref_clk_prop == 156) ||( ref_clk_prop == 1)) {
    253             pm_create_info.pm_specific_info.pm4x25.ref_clk = phymodRefClk156Mhz;
    254         } else if (ref_clk_prop == 125) {
    255             pm_create_info.pm_specific_info.pm4x25.ref_clk = phymodRefClk125Mhz;
    256         } else {
    257             LOG_ERROR(BSL_LS_SOC_PORT, (BSL_META_UP(unit, first_port,
    258                        "ERROR: This %d MHz clk freq is not supported.  Use 156MHz / 125MHz.\n"),ref_clk_prop));
    259             return SOC_E_PARAM ;
    260         }
    261 
    262         /* Add PM to PortMod */
    263         rv = portmod_port_macro_add(unit, &pm_create_info);
    264     }
    265 
    266     if (PORTMOD_FAILURE(rv)) {
    267         for (pmid=0; pmid < SOC_MV2_PM4X25_COUNT; pmid++) {
    268             if (pm4x25_mv2_user_acc[unit][pmid].mutex) {
    269                 sal_mutex_destroy(pm4x25_mv2_user_acc[unit][pmid].mutex);
    270                 pm4x25_mv2_user_acc[unit][pmid].mutex = NULL;
    271             }
    272         }
    273     }
    274 
    275     return rv;
    276 #else /* PORTMOD_PM4X25_SUPPORT */
    277     return SOC_E_UNAVAIL;
    278 #endif /* PORTMOD_PM4X25_SUPPORT */
    279 }
    280 
    281 #define MAVERICK2_FIRST_MGMT_PHYSICAL_PORT_NUM   81
    282 /* #define MAVERICK2_SECOND_MGMT_PHYSICAL_PORT_NUM  131 */
    283 STATIC int
    284 _soc_mv2_portctrl_pm4x10_portmod_init(int unit, int second_mgmt_port)
    285 {
    286 #ifdef PORTMOD_PM4X10_SUPPORT
    287     int rv = SOC_E_NONE;
    288     portmod_pm_create_info_t pm_create_info;
    289     int pmid = 0, blk, is_sim, lane, phy, found, logical_port;
    290     int idx, ref_clk_prop;
    291     uint32 txlane_map = 0x3210, rxlane_map = 0x3210;
    292     uint32 tx_polarity, rx_polarity;
    293     uint8_t pPort[] = {MAVERICK2_FIRST_MGMT_PHYSICAL_PORT_NUM, 0 /* unused */} ; 
    294 
    295     /* Allocate user access for all PMs */
    296     SOC_IF_ERROR_RETURN (soc_esw_portctrl_pm_user_access_alloc(unit, 
    297                   SOC_MV2_PM4X10_COUNT, &pm4x10_mv2_user_acc[unit]));
    298 
    299 
    300     for (pmid = 0; PORTMOD_SUCCESS(rv) && (pmid < SOC_MV2_PM4X10_COUNT); pmid++) {
    301 
    302         rv = portmod_pm_create_info_t_init(unit, &pm_create_info);
    303         if (PORTMOD_FAILURE(rv)) {
    304             break;
    305         }
    306 
    307         pm_create_info.type         = portmodDispatchTypePm4x10;
    308 
    309         SOC_PBMP_PORT_ADD(pm_create_info.phys, pPort[0]); /* first mgmt port */
    310         SOC_PBMP_PORT_ADD(pm_create_info.phys, pPort[0]+1);
    311         SOC_PBMP_PORT_ADD(pm_create_info.phys, pPort[0]+2);
    312         SOC_PBMP_PORT_ADD(pm_create_info.phys, pPort[0]+3);
    313         if (second_mgmt_port) {
    314             SOC_PBMP_PORT_ADD(pm_create_info.phys, pPort[1]); /* second mgmt port */
    315         }
    316 
    317         /* Identify the block for this particular port */
    318         found = 0;
    319 
    320         for(idx = 0; idx < SOC_DRIVER(unit)->port_num_blktype; idx++){
    321             blk = SOC_PORT_IDX_INFO(unit, pPort[0], idx).blk;
    322             if (SOC_BLOCK_INFO(unit, blk).type == SOC_BLK_XLPORT){
    323                 found = 1;
    324                 break;
    325             }
    326         }
    327 
    328         if (!found) {
    329             rv = SOC_E_INTERNAL;
    330             break;
    331         }
    332 
    333 
    334         /* Init user_acc for phymod access struct */
    335         rv = portmod_default_user_access_t_init(unit,
    336                                                 &(pm4x10_mv2_user_acc[unit][pmid]));
    337         if (PORTMOD_FAILURE(rv)) {
    338             break;
    339         }
    340 
    341         PORTMOD_USER_ACCESS_FW_LOAD_REVERSE_SET((&(pm4x10_mv2_user_acc[unit][pmid])));
    342         pm4x10_mv2_user_acc[unit][pmid].unit = unit;
    343         pm4x10_mv2_user_acc[unit][pmid].blk_id = blk;
    344         pm4x10_mv2_user_acc[unit][pmid].mutex = sal_mutex_create("core mutex");
    345 
    346         if (pm4x10_mv2_user_acc[unit][pmid].mutex == NULL) {
    347             rv = SOC_E_MEMORY;
    348             break;
    349         }
    350 
    351         /* Specific info for PM4x10 */
    352         rv = phymod_access_t_init(&pm_create_info.pm_specific_info.pm4x10.access);
    353         if (PORTMOD_FAILURE(rv)) {
    354             break;
    355         }
    356 
    357         pm_create_info.pm_specific_info.pm4x10.access.user_acc = &(pm4x10_mv2_user_acc[unit][pmid]);
    358         pm_create_info.pm_specific_info.pm4x10.access.addr     = _mv2_pm4x10_addr[pmid];
    359         pm_create_info.pm_specific_info.pm4x10.access.bus      = NULL; /* Use default bus */
    360         pm_create_info.pm_specific_info.pm4x10.rescal          = -1;
    361 
    362         rv = soc_physim_check_sim(unit, phymodDispatchTypeTsce,
    363                                   &(pm_create_info.pm_specific_info.pm4x10.access),
    364                                   0, &is_sim);
    365 
    366         if (PORTMOD_FAILURE(rv)) {
    367             break;
    368         }
    369 
    370         if (is_sim) {
    371             pm_create_info.pm_specific_info.pm4x10.access.bus->bus_capabilities |=
    372                 (PHYMOD_BUS_CAP_WR_MODIFY | PHYMOD_BUS_CAP_LANE_CTRL);
    373 
    374             /* Firmward loader : Don't allow FW load on sim enviroment */
    375             pm_create_info.pm_specific_info.pm4x10.fw_load_method =
    376                 phymodFirmwareLoadMethodNone;
    377         } else {
    378             pm_create_info.pm_specific_info.pm4x10.fw_load_method =
    379                 soc_property_suffix_num_get(unit, pmid,
    380                                             spn_LOAD_FIRMWARE, "quad",
    381                                             phymodFirmwareLoadMethodExternal);
    382             pm_create_info.pm_specific_info.pm4x10.fw_load_method &= 0xff;
    383         }
    384 
    385         /* Use default external loader if NULL */
    386         pm_create_info.pm_specific_info.pm4x10.external_fw_loader = NULL;
    387 
    388         /* Polarity */
    389         rv = phymod_polarity_t_init (&(pm_create_info.pm_specific_info.pm4x10.polarity));
    390         if (PORTMOD_FAILURE(rv)) {
    391             break;
    392         }
    393 
    394         for (lane = 0; lane < SOC_PM4X10_NUM_LANES; lane++) {
    395 
    396             if ((lane == 1) || (lane == 3)) continue;
    397             if ((lane == 2) && (!second_mgmt_port)) continue;
    398 
    399             if (lane > 1) {
    400                 rv = SOC_E_INTERNAL;
    401                 break;
    402             }
    403             
    404             phy = pPort[lane];
    405 
    406             logical_port = SOC_INFO(unit).port_p2l_mapping[phy];
    407 
    408             mv2_pm_port_polarity_get (unit, logical_port, phy, lane, &tx_polarity, &rx_polarity);
    409 
    410             pm_create_info.pm_specific_info.pm4x10.polarity.rx_polarity |= rx_polarity;
    411             pm_create_info.pm_specific_info.pm4x10.polarity.tx_polarity |= tx_polarity;
    412         }
    413 
    414         if (PORTMOD_FAILURE(rv)) {
    415             break;
    416         }
    417 
    418         /* Lane map */
    419         rv = phymod_lane_map_t_init
    420             (&(pm_create_info.pm_specific_info.pm4x10.lane_map));
    421         if (PORTMOD_FAILURE(rv)) {
    422             break;
    423         }
    424 
    425         logical_port = SOC_INFO(unit).port_p2l_mapping[pPort[0]];
    426 
    427         if (logical_port != -1) {
    428             mv2_pm_port_lanemap_get (unit, logical_port, pPort[0], &txlane_map, &rxlane_map);
    429         }
    430 
    431         pm_create_info.pm_specific_info.pm4x10.lane_map.num_of_lanes = SOC_PM4X10_NUM_LANES;
    432         pm_create_info.pm_specific_info.pm4x10.core_num = pmid; 
    433         pm_create_info.pm_specific_info.pm4x10.core_num_int = 0;
    434 
    435         for(lane=0 ; lane<SOC_PM4X10_NUM_LANES; lane++) {
    436             /*if ((lane == 1) || (lane == 3)) continue;    only 2 lanes connected
    437             if ((lane == 2) && (!second_mgmt_port)) continue;    lane 2 for mgmt only. **/
    438 
    439             pm_create_info.pm_specific_info.pm4x10.lane_map.lane_map_tx[lane] =
    440                 (txlane_map >> (lane * SOC_PM4X10_NUM_LANES)) &
    441                 SOC_PM4X10_LANE_MASK;
    442 
    443             pm_create_info.pm_specific_info.pm4x10.lane_map.lane_map_rx[lane] =
    444                 (rxlane_map >> (lane * SOC_PM4X10_NUM_LANES)) &
    445                 SOC_PM4X10_LANE_MASK;
    446         }
    447 
    448         ref_clk_prop = soc_property_port_get(unit, pPort[0],
    449                             spn_XGXS_LCPLL_XTAL_REFCLK, 156);
    450 
    451 
    452         if ((ref_clk_prop == 156) ||( ref_clk_prop == 1)) {
    453             pm_create_info.pm_specific_info.pm4x10.ref_clk = phymodRefClk156Mhz;
    454         } else if (ref_clk_prop == 125) {
    455             pm_create_info.pm_specific_info.pm4x10.ref_clk = phymodRefClk125Mhz;
    456         } else {
    457             LOG_ERROR(BSL_LS_SOC_PORT, (BSL_META_UP(unit, pPort[0],
    458                 "ERROR: %d MHz clk not valid. Use 156/125 MHz.\n"),ref_clk_prop));
    459             return SOC_E_PARAM ;
    460         }
    461 
    462         /* shim code for Mgmt port doesn't support single port mode
    463          * As a WAR, set 4-lanes port as dual-port mode
    464          */
    465         logical_port = SOC_INFO(unit).port_p2l_mapping[pPort[0]];
    466         if (SOC_INFO(unit).port_num_lanes[logical_port] == 4) {
    467             pm_create_info.pm_specific_info.pm4x10.port_mode_aux_info = portmodModeInfoTwoDualModePorts;
    468         }
    469 
    470         /* Add PM to PortMod */
    471         rv = portmod_port_macro_add(unit, &pm_create_info);
    472     }
    473 
    474     if (PORTMOD_FAILURE(rv)) {
    475         for (pmid=0; pmid < SOC_MV2_PM4X10_COUNT; pmid++) {
    476             if (pm4x10_mv2_user_acc[unit][pmid].mutex) {
    477                 sal_mutex_destroy(pm4x10_mv2_user_acc[unit][pmid].mutex);
    478                 pm4x10_mv2_user_acc[unit][pmid].mutex = NULL;
    479             }
    480         }
    481     }
    482 
    483     return rv;
    484 #else /* PORTMOD_PM4X10_SUPPORT */
    485     return SOC_E_UNAVAIL;
    486 #endif /* PORTMOD_PM4X10_SUPPORT */
    487 }
    488 
    489 /*
    490  * Function:
    491  *      soc_mv2_portctrl_pm_portmod_init
    492  * Purpose:
    493  *      Initialize PortMod and PortMacro for Trident2Plus
    494  *      Add port macros (PM) to the unit's PortMod Manager (PMM).
    495  * Parameters:
    496  *      unit             - (IN) Unit number.
    497  * Returns:
    498  *      SOC_E_XXX
    499  */
    500 int
    501 soc_mv2_portctrl_pm_portmod_init(int unit)
    502 {
    503     int    rv = SOC_E_NONE;
    504     uint32 flags = 0, mgmt_port_count = 0;
    505 
    506     /*
    507      * If portmod was create - destroy and create again
    508      * Better way would be to create once and leave it.
    509      */
    510     if (SOC_E_NONE == soc_esw_portctrl_init_check(unit)) {
    511         SOC_IF_ERROR_RETURN(portmod_destroy(unit));
    512     }
    513 
    514     PORTMOD_CREATE_F_PM_NULL_SET(flags);
    515 
    516     SOC_IF_ERROR_RETURN
    517         (portmod_create(unit, flags, SOC_MAX_NUM_PORTS, SOC_MV2_MAX_PHYS, 
    518                          sizeof(mv2_pm_types)/sizeof(portmod_pm_instances_t), mv2_pm_types));
    519 
    520     SOC_PBMP_COUNT(SOC_INFO(unit).management_pbm, mgmt_port_count);
    521 
    522     rv = _soc_mv2_portctrl_pm4x25_portmod_init (unit, (mgmt_port_count == 2) ? 1 : 0);
    523     if (rv) return (rv);
    524 
    525     return(_soc_mv2_portctrl_pm4x10_portmod_init (unit, (mgmt_port_count == 2) ? 1 : 0));
    526 }
    527 
    528 /*
    529  * Function:
    530  *      soc_mv2_portctrl_pm_portmod_deinit
    531  * Purpose:
    532  *      Deinitialize PortMod and PortMacro for Trident2Plus.
    533  *      Free pm user access data.
    534  * Parameters:
    535  *      unit      - (IN) Unit number.
    536  * Returns:
    537  *      SOC_E_NONE
    538  */
    539 int
    540 soc_mv2_portctrl_pm_portmod_deinit(int unit)
    541 {
    542     if (SOC_E_INIT == soc_esw_portctrl_init_check(unit)) {
    543         return SOC_E_NONE;
    544     }
    545 
    546     /* Free PMs structures */
    547 #ifdef PORTMOD_PM4X25_SUPPORT
    548     if (pm4x25_mv2_user_acc[unit] != NULL) {
    549         sal_free(pm4x25_mv2_user_acc[unit]);
    550         pm4x25_mv2_user_acc[unit] = NULL;
    551     }
    552 #endif /* PORTMOD_PM4X25_SUPPORT */
    553 
    554 #ifdef PORTMOD_PM4X10_SUPPORT
    555     if (pm4x10_mv2_user_acc[unit] != NULL) {
    556         sal_free(pm4x10_mv2_user_acc[unit]);
    557         pm4x10_mv2_user_acc[unit] = NULL;
    558     }
    559 #endif /* PORTMOD_PM4X10_SUPPORT */
    560 
    561     SOC_IF_ERROR_RETURN(portmod_destroy(unit));
    562 
    563     return SOC_E_NONE;
    564 }
    565 
    566 int
    567 soc_mv2_portctrl_pm_port_config_get(int unit, soc_port_t port, void *port_config)
    568 {
    569 #ifdef PORTMOD_PM4X25_SUPPORT
    570     int rv = SOC_E_NONE;
    571     int pmid = 0, lane, phy, phy_port, logical_port;
    572     int first_port = 0, core_num, core_count = 0, core_index, is_sim, type;
    573     uint32 txlane_map, rxlane_map, i;
    574     uint32 tx_polarity, rx_polarity;
    575     portmod_port_init_config_t *port_config_info;
    576     phymod_firmware_load_method_t fw_load_method;
    577     phymod_polarity_t polarity; /**< Lanes Polarity */
    578     phymod_lane_map_t lane_map;
    579 
    580     port_config_info = (portmod_port_init_config_t *)port_config;
    581 
    582     phy = SOC_INFO(unit).port_l2p_mapping[port];
    583 
    584     /* Find the port belong to which PM. The port has its own core id, using it to compare PM. */
    585     core_num = (phy - 1) / SOC_PM4X25_NUM_LANES;
    586 
    587     for (i=0; i<SOC_MV2_PM4X25_COUNT; i++) {
    588         if (core_num == i) {
    589             type   = portmodDispatchTypePm4x25;
    590             pmid = i;
    591             first_port = 1 + (pmid << 2);
    592             core_count = 1;
    593             break;
    594         }
    595     }
    596     /* When port dones't find PM4x25, find PM4x10 again. */
    597     if (i == SOC_MV2_PM4X25_COUNT) {
    598         for (i=0; i<SOC_MV2_PM4X10_COUNT; i++) {
    599             if (core_num == (31+i)) {
    600                 type = portmodDispatchTypePm4x10;
    601                 pmid = i;
    602                 core_count = 1;
    603                 first_port = 128 + pmid;
    604                 break;
    605             }
    606         }
    607     }
    608 
    609     for (core_index = 0; core_index < core_count; core_index++) {
    610         fw_load_method = phymodFirmwareLoadMethodExternal;
    611 
    612         soc_physim_enable_get(unit, &is_sim);
    613 
    614         if (is_sim) {
    615             /* Firmward loader : Don't allow FW load on sim enviroment */
    616             fw_load_method = phymodFirmwareLoadMethodNone;
    617         } else {
    618             fw_load_method = soc_property_suffix_num_get(unit, pmid,
    619                                             spn_LOAD_FIRMWARE, "quad",
    620                                             phymodFirmwareLoadMethodExternal);
    621             fw_load_method &= 0xff;
    622         }
    623 
    624         rv = phymod_polarity_t_init(&polarity);
    625         if (PORTMOD_FAILURE(rv)) {
    626             break;
    627         }
    628 
    629         /* Polarity */
    630         for (lane = 0; lane < SOC_PM4X25_NUM_LANES; lane++) {
    631             phy_port = first_port + lane + (core_index*4);
    632             logical_port = SOC_INFO(unit).port_p2l_mapping[phy_port];
    633         
    634             mv2_pm_port_polarity_get (unit, logical_port, phy_port, lane, &tx_polarity, &rx_polarity);
    635 
    636             polarity.rx_polarity |= rx_polarity;
    637             polarity.tx_polarity |= tx_polarity;
    638         }
    639 
    640         /* Lane map */
    641         rv = phymod_lane_map_t_init(&lane_map);
    642         if (PORTMOD_FAILURE(rv)) {
    643             break;
    644         }
    645 
    646         phy_port = first_port + (core_index*4);
    647         logical_port = SOC_INFO(unit).port_p2l_mapping[phy_port];
    648 
    649         mv2_pm_port_lanemap_get (unit, logical_port, first_port, &txlane_map, &rxlane_map);       
    650 
    651         lane_map.num_of_lanes = (type == portmodDispatchTypePm4x25) ?
    652                                  SOC_PM4X25_NUM_LANES : SOC_PM4X10_NUM_LANES;
    653 
    654         for(lane = 0 ; lane < lane_map.num_of_lanes; lane++) {
    655             lane_map.lane_map_tx[lane] =
    656                 (txlane_map >> (lane * lane_map.num_of_lanes)) &
    657                 SOC_PM4X25_LANE_MASK;
    658             lane_map.lane_map_rx[lane] =
    659                 (rxlane_map >> (lane * lane_map.num_of_lanes)) &
    660                 SOC_PM4X25_LANE_MASK;
    661         }
    662 
    663         sal_memcpy(&port_config_info->fw_load_method[core_index], &fw_load_method,
    664                     sizeof(phymod_firmware_load_method_t));
    665         port_config_info->fw_load_method_overwrite = 1;
    666         sal_memcpy(&port_config_info->polarity[core_index], &polarity,
    667                     sizeof(phymod_polarity_t));
    668         port_config_info->polarity_overwrite = 1;
    669         sal_memcpy(&port_config_info->lane_map[core_index], &lane_map,
    670                     sizeof(phymod_lane_map_t));
    671         port_config_info->lane_map_overwrite = 1;
    672     }
    673 
    674     return rv;
    675 #else /* PORTMOD_PM4X25_SUPPORT */
    676     return SOC_E_UNAVAIL;
    677 #endif /* PORTMOD_PM4X25_SUPPORT */
    678 }
    679 
    680 int
    681 soc_mv2_portctrl_pm_port_phyaddr_get(int unit, soc_port_t port)
    682 {
    683     int phy, core_index;
    684     uint32 pmid;
    685 
    686     phy = SOC_INFO(unit).port_l2p_mapping[port];
    687 
    688     /* Find the port belong to which PM. The port has its own core id, using it to compare PM. */
    689     core_index = (phy - 1) / SOC_PM4X25_NUM_LANES;
    690 
    691 #ifdef PORTMOD_PM4X25_SUPPORT
    692     /* When port dones't find PM4x10, find PM4x25 again. */
    693     for (pmid=0; pmid<SOC_MV2_PM4X25_COUNT; pmid++) {
    694         if (core_index == pmid) {
    695             return _mv2_pm4x25_addr[pmid];
    696         }
    697     }
    698 #endif /* PORTMOD_PM4X25_SUPPORT */
    699 
    700 #ifdef PORTMOD_PM4X10_SUPPORT
    701     for (pmid=0; pmid<SOC_MV2_PM4X10_COUNT; pmid++) {
    702         if (core_index == (31+pmid)) {
    703             return _mv2_pm4x10_addr[pmid];
    704         }
    705     }
    706 #endif /* PORTMOD_PM4X10_SUPPORT */
    707     return -1;
    708 }
    709 
    710 #define _MV2_PHY_PORT_MNG0              129
    711 int
    712 soc_mv2_portctrl_pm_type_get(int unit, soc_port_t phy_port, int* pm_type)
    713 {
    714     *pm_type = -1;
    715 
    716     if (phy_port >= 1 && phy_port <= 128) {
    717 #ifdef PORTMOD_PM4X25_SUPPORT
    718         *pm_type = portmodDispatchTypePm4x25;
    719         return (SOC_E_NONE);
    720 #endif
    721     } else if (phy_port == _MV2_PHY_PORT_MNG0) {
    722 #ifdef PORTMOD_PM4X10_SUPPORT
    723         *pm_type = portmodDispatchTypePm4x10;
    724         return (SOC_E_NONE);
    725 #endif
    726     } else {
    727         return(SOC_E_PARAM);
    728     }
    729 
    730     return SOC_E_UNAVAIL;
    731 }
    732 
    733 STATIC int
    734 _soc_mv2_portctrl_port_ability_update(int unit, soc_port_t port, soc_port_ability_t *ability)
    735 {
    736     uint32 max_lane_speed = 0;
    737 
    738     if (!soc_feature(unit, soc_feature_untethered_otp)) {
    739         return SOC_E_NONE;
    740     }
    741 
    742     SHR_BITCOPY_RANGE(&max_lane_speed, 0, SOC_BOND_INFO(unit)->tsc_max_speed,
    743                       SOC_INFO(unit).port_serdes[port] * 2, 2);
    744 
    745     /* Each PM4x25 TSC has two bit.
    746      * 00= no restrcition, 01= 27.9525G, 10=10.9375G, 11=reserved
    747      */
    748     if (max_lane_speed == 2) {
    749         ability->speed_full_duplex &= (SOC_PA_SPEED_1000MB | SOC_PA_SPEED_10GB |
    750                                        SOC_PA_SPEED_11GB);
    751     }
    752     return SOC_E_NONE;
    753 }
    754 
    755 soc_portctrl_functions_t soc_mv2_portctrl_func = {
    756     soc_mv2_portctrl_pm_portmod_init,
    757     soc_mv2_portctrl_pm_portmod_deinit,
    758     soc_mv2_portctrl_pm_port_config_get,
    759     soc_mv2_portctrl_pm_port_phyaddr_get,
    760     _soc_mv2_portctrl_port_ability_update,
    761     soc_mv2_portctrl_pm_type_get,
    762     NULL,
    763     NULL
    764 };
    765 
    766 #endif /* BCM_MAVERICK2_SUPPORT */