qtce16.c (67908B)
1 /* 2 * 3 * 4 * 5 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 6 * 7 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 8 */ 9 10 #include <phymod/phymod.h> 11 #include <phymod/phymod_system.h> 12 #include <phymod/phymod_dispatch.h> 13 #include <phymod/phymod_debug.h> 14 #include <phymod/phymod_util.h> 15 #include <phymod/chip/bcmi_qtce16_xgxs_defs.h> 16 #include <phymod/chip/merlin16.h> 17 18 #include "qtce16/tier1/qe16PCSRegEnums.h" 19 #include "qtce16/tier1/qmod16_enum_defines.h" 20 #include "qtce16/tier1/qmod16_device.h" 21 #include "qtce16/tier1/qmod16.h" 22 #include "qtce16/tier1/qmod16_defines.h" 23 #include "qtce16/tier1/qmod16_sc_lkup_table.h" 24 #include "qtce16/tier1/phy_tsc_iblk.h" 25 #include "merlin16/tier1/merlin16_cfg_seq.h" 26 #include "merlin16/tier1/merlin16_common.h" 27 #include "merlin16/tier1/merlin16_interface.h" 28 #include "merlin16/tier1/merlin16_dependencies.h" 29 #include "merlin16/tier1/merlin16_internal.h" 30 31 #ifdef PHYMOD_QTCE16_SUPPORT 32 33 #define QTCE16_ID0 0x600d 34 #define QTCE16_ID1 0x8770 35 #define QTCE16_REV_MASK 0x0 36 37 #define QTCE16_MODEL 0x16 38 39 #define QTCE16_NOF_DFES (5) 40 #define QTCE16_NOF_LANES_IN_CORE (4) 41 #define QTCE16_LANE_SWAP_LANE_MASK (0x3) 42 #define QTCE16_PHY_ALL_LANES (0xf) 43 #define QTCE16_CORE_TO_PHY_ACCESS(_phy_access, _core_access) \ 44 do{\ 45 PHYMOD_MEMCPY(&(_phy_access)->access, &(_core_access)->access, sizeof((_phy_access)->access));\ 46 (_phy_access)->type = (_core_access)->type; \ 47 (_phy_access)->access.lane_mask = QTCE16_PHY_ALL_LANES; \ 48 }while(0) 49 50 extern unsigned char merlin16_ucode[]; 51 extern unsigned short merlin16_ucode_ver; 52 extern unsigned short merlin16_ucode_crc; 53 extern unsigned short merlin16_ucode_len; 54 55 STATIC 56 int _qtce16_phy_firmware_lane_config_set(const phymod_phy_access_t* phy, phymod_firmware_lane_config_t fw_config) 57 { 58 struct merlin16_uc_lane_config_st serdes_firmware_config; 59 phymod_phy_access_t phy_copy; 60 int start_lane, num_lane, i; 61 /* uint32_t rst_status; */ 62 uint32_t is_warm_boot; 63 64 PHYMOD_IF_ERR_RETURN 65 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 66 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 67 68 for (i = 0; i < num_lane; i++) { 69 phy_copy.access.lane_mask = 1 << (start_lane + i); 70 serdes_firmware_config.field.lane_cfg_from_pcs = fw_config.LaneConfigFromPCS; 71 serdes_firmware_config.field.an_enabled = fw_config.AnEnabled; 72 serdes_firmware_config.field.dfe_on = fw_config.DfeOn; 73 serdes_firmware_config.field.force_brdfe_on = fw_config.ForceBrDfe; 74 /* serdes_firmware_config.field.cl72_emulation_en = fw_config.Cl72Enable; */ 75 serdes_firmware_config.field.scrambling_dis = fw_config.ScramblingDisable; 76 serdes_firmware_config.field.unreliable_los = fw_config.UnreliableLos; 77 serdes_firmware_config.field.media_type = fw_config.MediaType; 78 79 PHYMOD_IF_ERR_RETURN(PHYMOD_IS_WRITE_DISABLED(&phy_copy.access, &is_warm_boot)); 80 81 if (!is_warm_boot) { 82 PHYMOD_IF_ERR_RETURN (merlin16_set_uc_lane_cfg(&phy_copy.access, serdes_firmware_config)); 83 } 84 } 85 return PHYMOD_E_NONE; 86 } 87 88 int qtce16_core_identify(const phymod_core_access_t* core, uint32_t core_id, uint32_t* is_identified) 89 { 90 int ioerr = 0; 91 const phymod_access_t *pm_acc = &core->access; 92 PHYID2r_t id2; 93 PHYID3r_t id3; 94 MAIN_SERDESIDr_t serdesid; 95 /* DIG_REVID0r_t revid; */ 96 uint32_t model; 97 int rv ; 98 *is_identified = 0; 99 100 if(core_id == 0){ 101 ioerr += READ_PHYID2r(pm_acc, &id2); 102 ioerr += READ_PHYID3r(pm_acc, &id3); 103 } 104 else{ 105 PHYID2r_SET(id2, ((core_id >> 16) & 0xffff)); 106 PHYID3r_SET(id3, core_id & 0xffff); 107 } 108 109 if (PHYID2r_GET(id2) == QTCE16_ID0 && 110 (PHYID3r_GET(id3) &= ~QTCE16_REV_MASK) == QTCE16_ID1) { 111 /* PHY IDs match - now check PCS model */ 112 ioerr += READ_MAIN_SERDESIDr(pm_acc, &serdesid); 113 model = MAIN_SERDESIDr_MODEL_NUMBERf_GET(serdesid); 114 if (model == QTCE16_MODEL) { 115 *is_identified = 1; 116 } 117 } 118 rv = ioerr ? PHYMOD_E_IO : PHYMOD_E_NONE; 119 return rv ; 120 } 121 122 123 int qtce16_core_info_get(const phymod_core_access_t* phy, phymod_core_info_t* info) 124 { 125 uint32_t serdes_id; 126 PHYID2r_t id2; 127 PHYID3r_t id3; 128 const phymod_access_t *pm_acc = &phy->access; 129 PHYMOD_IF_ERR_RETURN 130 (qmod16_revid_read(&phy->access, &serdes_id)); 131 info->serdes_id = serdes_id; 132 if ((serdes_id & 0x3f) == QTCE16_MODEL) { 133 info->core_version = phymodCoreVersionQtce16; 134 PHYMOD_STRNCPY(info->name, "Qtce16", PHYMOD_STRLEN("Qtce16")+1); /* need to remove when the master rev*/ 135 } 136 /* need to update with the master rev 137 PHYMOD_IF_ERR_RETURN 138 (phymod_core_name_get(phy, serdes_id, core_name, info)); 139 */ 140 141 PHYMOD_IF_ERR_RETURN(READ_PHYID2r(pm_acc, &id2)); 142 PHYMOD_IF_ERR_RETURN(READ_PHYID3r(pm_acc, &id3)); 143 144 info->phy_id0 = (uint16_t) id2.v[0]; 145 info->phy_id1 = (uint16_t) id3.v[0]; 146 return PHYMOD_E_NONE; 147 } 148 149 /* 150 * set lane swapping for core 151 * The tx swap is composed of tx PCS swap. 152 * The rx swap is composed of rx PCS swap 153 * 154 * lane_map_tx and lane_map_rx[lane=logic_lane] are logic-lane base. 155 * pcs_swap and register is logic_lane base. 156 */ 157 int qtce16_core_lane_map_set(const phymod_core_access_t* core, const phymod_lane_map_t* lane_map) 158 { 159 uint32_t pcs_rx_swap = 0 , pcs_tx_swap = 0, lane; 160 uint8_t pmd_tx_lane_map[PHYMOD_MAX_LANES_PER_CORE]; 161 uint8_t pmd_rx_lane_map[PHYMOD_MAX_LANES_PER_CORE]; 162 uint8_t num_lanes = (uint8_t) lane_map->num_of_lanes; 163 164 if(lane_map->num_of_lanes != QTCE16_NOF_LANES_IN_CORE){ 165 return PHYMOD_E_CONFIG; 166 } 167 for( lane = 0 ; lane < QTCE16_NOF_LANES_IN_CORE ; lane++){ 168 if(lane_map->lane_map_rx[lane] >= QTCE16_NOF_LANES_IN_CORE){ 169 return PHYMOD_E_CONFIG; 170 } 171 /* encode each lane as four bits */ 172 /* pcs_rx_map[lane] = rx_map[lane] */ 173 pcs_rx_swap += lane_map->lane_map_rx[lane]<<(lane*4); 174 } 175 176 for( lane = 0 ; lane < QTCE16_NOF_LANES_IN_CORE ; lane++){ 177 if(lane_map->lane_map_tx[lane] >= QTCE16_NOF_LANES_IN_CORE){ 178 return PHYMOD_E_CONFIG; 179 } 180 pcs_tx_swap += lane_map->lane_map_tx[lane]<<(lane*4); 181 } 182 183 for (lane = 0; lane < QTCE16_NOF_LANES_IN_CORE; lane++) { 184 pmd_tx_lane_map[(int)lane_map->lane_map_tx[lane]] = lane; 185 pmd_rx_lane_map[(int)lane_map->lane_map_rx[lane]] = lane; 186 } 187 188 189 PHYMOD_IF_ERR_RETURN(qmod16_pcs_lane_swap(&core->access, pcs_tx_swap, pcs_rx_swap)); 190 191 PHYMOD_IF_ERR_RETURN 192 (merlin16_map_lanes(&core->access, num_lanes, pmd_tx_lane_map, pmd_rx_lane_map)); 193 194 return PHYMOD_E_NONE; 195 } 196 197 int qtce16_core_lane_map_get(const phymod_core_access_t* core, phymod_lane_map_t* lane_map) 198 { 199 uint32_t pcs_tx_swap = 0 , pcs_rx_swap = 0, lane; 200 PHYMOD_IF_ERR_RETURN(qmod16_pcs_lane_swap_get(&core->access, &pcs_tx_swap, &pcs_rx_swap)); 201 for( lane = 0 ; lane < QTCE16_NOF_LANES_IN_CORE ; lane++){ 202 /* deccode each lane from four bits */ 203 lane_map->lane_map_rx[lane] = (pcs_rx_swap>>(lane*4)) & QTCE16_LANE_SWAP_LANE_MASK; 204 205 lane_map->lane_map_tx[lane] = (pcs_tx_swap>>(lane*4)) & QTCE16_LANE_SWAP_LANE_MASK; 206 } 207 lane_map->num_of_lanes = QTCE16_NOF_LANES_IN_CORE; 208 return PHYMOD_E_NONE; 209 } 210 211 212 int qtce16_core_firmware_info_get(const phymod_core_access_t* core, phymod_core_firmware_info_t* fw_info) 213 { 214 /* 215 * It's O.K to use this code as is since the firmware CRC is already checked at 216 * at the time we load it. 217 */ 218 fw_info->fw_crc = merlin16_ucode_crc; 219 fw_info->fw_version = merlin16_ucode_ver; 220 return PHYMOD_E_NONE; 221 222 } 223 /* load qtce16 fw. the fw_loader parameter is valid just for external fw load */ 224 STATIC 225 int _qtce16_core_firmware_load(const phymod_core_access_t* core, phymod_firmware_load_method_t load_method, phymod_firmware_loader_f fw_loader) 226 { 227 228 229 switch(load_method){ 230 case phymodFirmwareLoadMethodInternal: 231 PHYMOD_IF_ERR_RETURN(merlin16_ucode_mdio_load(&core->access, merlin16_ucode, merlin16_ucode_len)); 232 break; 233 case phymodFirmwareLoadMethodExternal: 234 PHYMOD_NULL_CHECK(fw_loader); 235 236 PHYMOD_IF_ERR_RETURN(merlin16_ucode_pram_load_pre(&core->access)); 237 PHYMOD_IF_ERR_RETURN(fw_loader(core, merlin16_ucode_len, merlin16_ucode)); 238 PHYMOD_IF_ERR_RETURN(merlin16_ucode_pram_load_post(&core->access)); 239 break; 240 case phymodFirmwareLoadMethodNone: 241 break; 242 default: 243 PHYMOD_RETURN_WITH_ERR(PHYMOD_E_CONFIG, (_PHYMOD_MSG("illegal fw load method %u"), load_method)); 244 } 245 return PHYMOD_E_NONE; 246 } 247 248 249 int qtce16_phy_firmware_core_config_set(const phymod_phy_access_t* phy, phymod_firmware_core_config_t fw_config) 250 { 251 struct merlin16_uc_core_config_st serdes_firmware_core_config; 252 PHYMOD_MEMSET(&serdes_firmware_core_config, 0, sizeof(serdes_firmware_core_config)); 253 serdes_firmware_core_config.field.core_cfg_from_pcs = fw_config.CoreConfigFromPCS; 254 serdes_firmware_core_config.field.vco_rate = fw_config.VcoRate; 255 256 PHYMOD_IF_ERR_RETURN(merlin16_INTERNAL_set_uc_core_config(&phy->access, serdes_firmware_core_config)); 257 return PHYMOD_E_NONE; 258 } 259 260 int qtce16_phy_firmware_core_config_get(const phymod_phy_access_t* phy, phymod_firmware_core_config_t* fw_config) 261 { 262 struct merlin16_uc_core_config_st serdes_firmware_core_config; 263 PHYMOD_IF_ERR_RETURN(merlin16_get_uc_core_config(&phy->access, &serdes_firmware_core_config)); 264 PHYMOD_MEMSET(fw_config, 0, sizeof(*fw_config)); 265 fw_config->CoreConfigFromPCS = serdes_firmware_core_config.field.core_cfg_from_pcs; 266 fw_config->VcoRate = serdes_firmware_core_config.field.vco_rate; 267 return PHYMOD_E_NONE; 268 } 269 270 271 int qtce16_phy_firmware_lane_config_set(const phymod_phy_access_t* phy, phymod_firmware_lane_config_t fw_lane_config) 272 { 273 phymod_phy_access_t phy_copy; 274 int start_lane, num_lane, i, lane_id, sub_port; 275 276 PHYMOD_IF_ERR_RETURN 277 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 278 PHYMOD_IF_ERR_RETURN 279 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 280 start_lane = lane_id; 281 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 282 283 /*Hold the per lne soft reset bit*/ 284 for (i = 0; i < num_lane; i++) { 285 phy_copy.access.lane_mask = 1 << (start_lane + i); 286 PHYMOD_IF_ERR_RETURN 287 (merlin16_lane_soft_reset_release(&phy_copy.access, 0)); 288 } 289 290 for (i = 0; i < num_lane; i++) { 291 phy_copy.access.lane_mask = 1 << (start_lane + i); 292 PHYMOD_IF_ERR_RETURN 293 (_qtce16_phy_firmware_lane_config_set(&phy_copy, fw_lane_config)); 294 } 295 /*Hold the per lne soft reset bit*/ 296 for (i = 0; i < num_lane; i++) { 297 phy_copy.access.lane_mask = 1 << (start_lane + i); 298 PHYMOD_IF_ERR_RETURN 299 (merlin16_lane_soft_reset_release(&phy_copy.access, 1)); 300 } 301 302 /* no need to set speed trigger here */ 303 return PHYMOD_E_NONE; 304 } 305 306 int qtce16_phy_firmware_lane_config_get(const phymod_phy_access_t* phy, phymod_firmware_lane_config_t* fw_config) 307 { 308 309 struct merlin16_uc_lane_config_st serdes_firmware_config; 310 phymod_phy_access_t phy_copy; 311 int lane_id, sub_port; 312 313 PHYMOD_IF_ERR_RETURN 314 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 315 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 316 phy_copy.access.lane_mask = 1 << lane_id; 317 318 PHYMOD_IF_ERR_RETURN(merlin16_get_uc_lane_cfg(&phy_copy.access, &serdes_firmware_config)); 319 PHYMOD_MEMSET(fw_config, 0, sizeof(*fw_config)); 320 fw_config->LaneConfigFromPCS = serdes_firmware_config.field.lane_cfg_from_pcs; 321 fw_config->AnEnabled = serdes_firmware_config.field.an_enabled; 322 fw_config->DfeOn = serdes_firmware_config.field.dfe_on; 323 fw_config->ForceBrDfe = serdes_firmware_config.field.force_brdfe_on; 324 fw_config->Cl72AutoPolEn = serdes_firmware_config.field.cl72_auto_polarity_en; 325 fw_config->Cl72RestTO = serdes_firmware_config.field.cl72_restart_timeout_en; 326 fw_config->ScramblingDisable = serdes_firmware_config.field.scrambling_dis; 327 fw_config->UnreliableLos = serdes_firmware_config.field.unreliable_los; 328 fw_config->MediaType = serdes_firmware_config.field.media_type; 329 330 return PHYMOD_E_NONE; 331 } 332 333 int qtce16_phy_polarity_set(const phymod_phy_access_t* phy, const phymod_polarity_t* polarity) 334 { 335 phymod_phy_access_t phy_copy; 336 int lane_id, sub_port; 337 338 PHYMOD_IF_ERR_RETURN 339 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 340 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 341 phy_copy.access.lane_mask = 1 << lane_id; 342 343 PHYMOD_IF_ERR_RETURN 344 (qmod16_tx_rx_polarity_set(&phy_copy.access, polarity->tx_polarity, polarity->rx_polarity)); 345 346 return PHYMOD_E_NONE; 347 348 } 349 350 int qtce16_phy_polarity_get(const phymod_phy_access_t* phy, phymod_polarity_t* polarity) 351 { 352 phymod_phy_access_t phy_copy; 353 int lane_id, sub_port; 354 355 PHYMOD_IF_ERR_RETURN 356 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 357 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 358 phy_copy.access.lane_mask = 1 << lane_id; 359 360 PHYMOD_IF_ERR_RETURN 361 (qmod16_tx_rx_polarity_get(&phy_copy.access, &polarity->tx_polarity, &polarity->rx_polarity)); 362 363 return PHYMOD_E_NONE; 364 } 365 366 367 int qtce16_phy_tx_set(const phymod_phy_access_t* phy, const phymod_tx_t* tx) 368 { 369 phymod_phy_access_t phy_copy; 370 int lane_id, sub_port; 371 372 PHYMOD_IF_ERR_RETURN 373 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 374 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 375 phy_copy.access.lane_mask = 1 << lane_id; 376 377 PHYMOD_IF_ERR_RETURN 378 (merlin16_apply_txfir_cfg(&phy_copy.access, (int8_t)tx->pre, (int8_t)tx->main, (int8_t)tx->post, (int8_t)tx->post2)); 379 return PHYMOD_E_NONE; 380 } 381 382 int qtce16_phy_tx_get(const phymod_phy_access_t* phy, phymod_tx_t* tx) 383 { 384 phymod_phy_access_t phy_copy; 385 int lane_id, sub_port; 386 int8_t value = 0; 387 388 PHYMOD_IF_ERR_RETURN 389 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 390 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 391 phy_copy.access.lane_mask = 1 << lane_id; 392 393 PHYMOD_IF_ERR_RETURN 394 (merlin16_read_tx_afe(&phy_copy.access, TX_AFE_PRE, &value)); 395 tx->pre = value; 396 PHYMOD_IF_ERR_RETURN 397 (merlin16_read_tx_afe(&phy_copy.access, TX_AFE_MAIN, &value)); 398 tx->main = value; 399 PHYMOD_IF_ERR_RETURN 400 (merlin16_read_tx_afe(&phy_copy.access, TX_AFE_POST1, &value)); 401 tx->post = value; 402 PHYMOD_IF_ERR_RETURN 403 (merlin16_read_tx_afe(&phy_copy.access, TX_AFE_POST2, &value)); 404 tx->post2 = value; 405 406 return PHYMOD_E_NONE; 407 } 408 409 int qtce16_phy_cl72_set(const phymod_phy_access_t* phy, uint32_t cl72_en) 410 { 411 struct merlin16_uc_lane_config_st serdes_firmware_config; 412 phymod_phy_access_t phy_copy; 413 int lane_id, sub_port; 414 415 PHYMOD_IF_ERR_RETURN 416 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 417 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 418 phy_copy.access.lane_mask = 1 << lane_id; 419 420 PHYMOD_IF_ERR_RETURN(merlin16_get_uc_lane_cfg(&phy_copy.access, &serdes_firmware_config)); 421 422 if (serdes_firmware_config.field.dfe_on == 0) { 423 PHYMOD_DEBUG_ERROR(("ERROR :: DFE is off : Can not start CL72 with no DFE\n")); 424 return PHYMOD_E_CONFIG; 425 } 426 427 PHYMOD_IF_ERR_RETURN 428 (qmod16_clause72_control(&phy->access, cl72_en)); 429 430 return PHYMOD_E_NONE; 431 } 432 433 int qtce16_phy_cl72_get(const phymod_phy_access_t* phy, uint32_t* cl72_en) 434 { 435 phymod_phy_access_t phy_copy; 436 int lane_id, sub_port; 437 438 PHYMOD_IF_ERR_RETURN 439 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 440 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 441 phy_copy.access.lane_mask = 1 << lane_id; 442 443 PHYMOD_IF_ERR_RETURN 444 (merlin16_pmd_cl72_enable_get(&phy_copy.access, cl72_en)); 445 446 return PHYMOD_E_NONE; 447 } 448 449 int qtce16_phy_cl72_status_get(const phymod_phy_access_t* phy, phymod_cl72_status_t* status) 450 { 451 uint32_t local_status; 452 phymod_phy_access_t phy_copy; 453 int lane_id, sub_port; 454 455 PHYMOD_IF_ERR_RETURN 456 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 457 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 458 phy_copy.access.lane_mask = 1 << lane_id; 459 460 PHYMOD_IF_ERR_RETURN 461 (merlin16_pmd_cl72_receiver_status(&phy_copy.access, &local_status)); 462 status->locked = local_status; 463 464 return PHYMOD_E_NONE; 465 } 466 467 int qtce16_phy_tx_lane_control_set(const phymod_phy_access_t* phy, phymod_phy_tx_lane_control_t tx_control) 468 { 469 phymod_phy_access_t pm_phy_copy; 470 int start_lane, num_lane, lane_id, sub_port; 471 int qmode = 0, subports = 0, sq_value = 0; 472 473 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 474 /* next program the tx fir taps and driver current based on the input */ 475 PHYMOD_IF_ERR_RETURN 476 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 477 478 PHYMOD_IF_ERR_RETURN 479 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 480 481 start_lane = lane_id ; 482 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 483 484 if (PHYMOD_ACC_F_QMODE_GET(&phy->access) || PHYMOD_ACC_F_USXMODE_GET(&phy->access)) { 485 qmode = 1; 486 PHYMOD_IF_ERR_RETURN(qmod16_port_state_get(&pm_phy_copy.access, QMOD16_PORT_STATE_CONFIGED, &subports)); 487 } 488 489 switch (tx_control) { 490 case phymodTxTrafficDisable: 491 PHYMOD_IF_ERR_RETURN(qmod16_tx_lane_control_set(&pm_phy_copy.access, QMOD16_TX_LANE_TRAFFIC_DISABLE)); 492 break; 493 case phymodTxTrafficEnable: 494 PHYMOD_IF_ERR_RETURN(qmod16_tx_lane_control_set(&pm_phy_copy.access, QMOD16_TX_LANE_TRAFFIC_ENABLE)); 495 break; 496 case phymodTxReset: 497 PHYMOD_IF_ERR_RETURN(qmod16_tx_lane_control_set(&pm_phy_copy.access, QMOD16_TX_LANE_RESET)); 498 break; 499 case phymodTxSquelchOn: 500 PHYMOD_IF_ERR_RETURN(qmod16_port_state_set(&pm_phy_copy.access, QMOD16_PORT_STATE_TX_SQUELCH, sub_port, 1)); 501 PHYMOD_IF_ERR_RETURN(qmod16_port_state_get(&pm_phy_copy.access, QMOD16_PORT_STATE_TX_SQUELCH, &sq_value)); 502 if ((qmode == 0) || (sq_value == subports)) { 503 /* not qmode or all subports want to squelch*/ 504 PHYMOD_IF_ERR_RETURN(qmod16_tx_squelch_set(&pm_phy_copy.access, 1)); 505 } 506 break; 507 case phymodTxSquelchOff: 508 PHYMOD_IF_ERR_RETURN(qmod16_port_state_set(&pm_phy_copy.access, QMOD16_PORT_STATE_TX_SQUELCH, sub_port, 0)); 509 PHYMOD_IF_ERR_RETURN(qmod16_tx_squelch_set(&pm_phy_copy.access, 0)); 510 break; 511 default: 512 break; 513 } 514 return PHYMOD_E_NONE; 515 516 } 517 518 int qtce16_phy_tx_lane_control_get(const phymod_phy_access_t* phy, phymod_phy_tx_lane_control_t* tx_control) 519 { 520 int enable, reset, tx_lane; 521 uint32_t lb_enable; 522 phymod_phy_access_t pm_phy_copy; 523 int start_lane, num_lane, lane_id, sub_port; 524 525 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 526 /* next program the tx fir taps and driver current based on the input */ 527 PHYMOD_IF_ERR_RETURN 528 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 529 530 PHYMOD_IF_ERR_RETURN 531 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 532 start_lane = lane_id ; 533 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 534 535 PHYMOD_IF_ERR_RETURN(qmod16_tx_squelch_get(&pm_phy_copy.access, &enable)); 536 537 /* next check if PMD loopback is on */ 538 if (enable) { 539 PHYMOD_IF_ERR_RETURN(merlin16_pmd_loopback_get(&pm_phy_copy.access, &lb_enable)); 540 if (lb_enable) enable = 0; 541 } 542 543 if(enable) { 544 *tx_control = phymodTxSquelchOn; 545 } else { 546 PHYMOD_IF_ERR_RETURN(qmod16_tx_lane_control_get(&pm_phy_copy.access, &reset, &tx_lane)); 547 if (!reset) { 548 *tx_control = phymodTxReset; 549 } else if (!tx_lane) { 550 *tx_control = phymodTxTrafficDisable; 551 } else { 552 *tx_control = phymodTxTrafficEnable; 553 } 554 } 555 556 return PHYMOD_E_NONE; 557 558 } 559 560 561 int qtce16_phy_rx_lane_control_set(const phymod_phy_access_t* phy, phymod_phy_rx_lane_control_t rx_control) 562 { 563 phymod_phy_access_t pm_phy_copy; 564 int start_lane, num_lane, lane_id, sub_port; 565 int qmode = 0, subports = 0, sq_value = 0; 566 567 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 568 /* next program the tx fir taps and driver current based on the input */ 569 PHYMOD_IF_ERR_RETURN 570 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 571 572 PHYMOD_IF_ERR_RETURN 573 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 574 575 start_lane = lane_id ; 576 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 577 578 if (PHYMOD_ACC_F_QMODE_GET(&phy->access) || PHYMOD_ACC_F_USXMODE_GET(&phy->access)) { 579 qmode = 1; 580 PHYMOD_IF_ERR_RETURN(qmod16_port_state_get(&pm_phy_copy.access, QMOD16_PORT_STATE_CONFIGED, &subports)); 581 } 582 switch (rx_control) { 583 case phymodRxReset: 584 PHYMOD_IF_ERR_RETURN(qmod16_rx_lane_control_set(&pm_phy_copy.access, 1)); 585 break; 586 case phymodRxSquelchOn: 587 PHYMOD_IF_ERR_RETURN(qmod16_port_state_set(&pm_phy_copy.access, QMOD16_PORT_STATE_RX_SQUELCH, sub_port, 1)); 588 PHYMOD_IF_ERR_RETURN(qmod16_port_state_get(&pm_phy_copy.access, QMOD16_PORT_STATE_RX_SQUELCH, &sq_value)); 589 if ((qmode == 0) || (sq_value == subports)) { 590 /* not qmode or all subports want to squelch */ 591 PHYMOD_IF_ERR_RETURN(qmod16_rx_squelch_set(&pm_phy_copy.access, 1)); 592 } 593 break; 594 case phymodRxSquelchOff: 595 PHYMOD_IF_ERR_RETURN(qmod16_port_state_set(&pm_phy_copy.access, QMOD16_PORT_STATE_RX_SQUELCH, sub_port, 0)); 596 PHYMOD_IF_ERR_RETURN(qmod16_rx_squelch_set(&pm_phy_copy.access, 0)); 597 break; 598 default: 599 break; 600 } 601 return PHYMOD_E_NONE; 602 603 } 604 605 int qtce16_phy_rx_lane_control_get(const phymod_phy_access_t* phy, phymod_phy_rx_lane_control_t* rx_control) 606 { 607 int enable, reset; 608 uint32_t lb_enable; 609 phymod_phy_access_t pm_phy_copy; 610 int start_lane, num_lane, lane_id, sub_port; 611 612 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 613 /* next program the tx fir taps and driver current based on the input */ 614 PHYMOD_IF_ERR_RETURN 615 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 616 617 PHYMOD_IF_ERR_RETURN 618 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 619 620 start_lane = lane_id ; 621 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 622 623 PHYMOD_IF_ERR_RETURN(qmod16_rx_squelch_get(&pm_phy_copy.access, &enable)); 624 /* next check if PMD loopback is on */ 625 if (enable) { 626 PHYMOD_IF_ERR_RETURN(merlin16_pmd_loopback_get(&pm_phy_copy.access, &lb_enable)); 627 if (lb_enable) enable = 0; 628 } 629 if(enable) { 630 *rx_control = phymodRxSquelchOn; 631 } else { 632 PHYMOD_IF_ERR_RETURN(qmod16_rx_lane_control_get(&pm_phy_copy.access, &reset)); 633 if (reset == 0) { 634 *rx_control = phymodRxReset; 635 } else { 636 *rx_control = phymodRxSquelchOff; 637 } 638 } 639 return PHYMOD_E_NONE; 640 } 641 642 int qtce16_phy_power_set(const phymod_phy_access_t* phy, const phymod_phy_power_t* power) 643 { 644 phymod_phy_access_t pm_phy_copy; 645 int start_lane, num_lane, lane_id, sub_port; 646 647 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 648 /* next program the tx fir taps and driver current based on the input */ 649 PHYMOD_IF_ERR_RETURN 650 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 651 652 PHYMOD_IF_ERR_RETURN 653 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 654 655 start_lane = lane_id ; 656 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 657 658 659 if ((power->tx == phymodPowerOff) && (power->rx == phymodPowerOff)) { 660 PHYMOD_IF_ERR_RETURN(qmod16_port_enable_set(&pm_phy_copy.access, 0)); 661 } 662 if ((power->tx == phymodPowerOn) && (power->rx == phymodPowerOn)) { 663 PHYMOD_IF_ERR_RETURN(qmod16_port_enable_set(&pm_phy_copy.access, 1)); 664 } 665 666 if ((power->tx == phymodPowerOff) && (power->rx == phymodPowerNoChange)) { 667 /* disable tx on the PMD side */ 668 PHYMOD_IF_ERR_RETURN(merlin16_tx_disable(&pm_phy_copy.access, 1)); 669 } 670 if ((power->tx == phymodPowerOn) && (power->rx == phymodPowerNoChange)) { 671 /* enable tx on the PMD side */ 672 PHYMOD_IF_ERR_RETURN(merlin16_tx_disable(&pm_phy_copy.access, 0)); 673 } 674 if ((power->tx == phymodPowerNoChange) && (power->rx == phymodPowerOff)) { 675 /* disable rx on the PMD side */ 676 PHYMOD_IF_ERR_RETURN(qmod16_rx_squelch_set(&pm_phy_copy.access, 1)); 677 } 678 if ((power->tx == phymodPowerNoChange) && (power->rx == phymodPowerOn)) { 679 /* enable rx on the PMD side */ 680 PHYMOD_IF_ERR_RETURN(qmod16_rx_squelch_set(&pm_phy_copy.access, 0)); 681 } 682 return PHYMOD_E_NONE; 683 684 } 685 686 int qtce16_phy_power_get(const phymod_phy_access_t* phy, phymod_phy_power_t* power) 687 { 688 int enable; 689 uint32_t lb_enable; 690 phymod_phy_access_t pm_phy_copy; 691 int start_lane, num_lane, lane_id, sub_port; 692 693 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 694 /* next program the tx fir taps and driver current based on the input */ 695 PHYMOD_IF_ERR_RETURN 696 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 697 698 PHYMOD_IF_ERR_RETURN 699 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 700 701 start_lane = lane_id ; 702 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 703 704 PHYMOD_IF_ERR_RETURN(qmod16_rx_squelch_get(&pm_phy_copy.access, &enable)); 705 706 /* next check if PMD loopback is on */ 707 if (enable) { 708 PHYMOD_IF_ERR_RETURN(merlin16_pmd_loopback_get(&pm_phy_copy.access, &lb_enable)); 709 if (lb_enable) enable = 0; 710 } 711 712 power->rx = (enable == 1)? phymodPowerOff: phymodPowerOn; 713 power->tx = (enable == 1)? phymodPowerOff: phymodPowerOn; 714 715 return PHYMOD_E_NONE; 716 } 717 718 int _qtce16_pll_multiplier_get(uint32_t pll_div, uint32_t *pll_multiplier) 719 { 720 switch (pll_div) { 721 case 0x0: 722 *pll_multiplier = 46; 723 break; 724 case 0x1: 725 *pll_multiplier = 72; 726 break; 727 case QMOD16_PLL_MODE_DIV_40: 728 *pll_multiplier = 40; 729 break; 730 case QMOD16_PLL_MODE_DIV_42: 731 *pll_multiplier = 42; 732 break; 733 case QMOD16_PLL_MODE_DIV_48: 734 *pll_multiplier = 48; 735 break; 736 case 0x5: 737 *pll_multiplier = 50; 738 break; 739 case QMOD16_PLL_MODE_DIV_52: 740 *pll_multiplier = 52; 741 break; 742 case QMOD16_PLL_MODE_DIV_54: 743 *pll_multiplier = 54; 744 break; 745 case QMOD16_PLL_MODE_DIV_60: 746 *pll_multiplier = 60; 747 break; 748 case QMOD16_PLL_MODE_DIV_64: 749 *pll_multiplier = 64; 750 break; 751 case QMOD16_PLL_MODE_DIV_66: 752 *pll_multiplier = 66; 753 break; 754 case 0xb: 755 *pll_multiplier = 68; 756 break; 757 case QMOD16_PLL_MODE_DIV_70: 758 *pll_multiplier = 70; 759 break; 760 case QMOD16_PLL_MODE_DIV_80: 761 *pll_multiplier = 80; 762 break; 763 case QMOD16_PLL_MODE_DIV_92: 764 *pll_multiplier = 92; 765 break; 766 case 0xf: 767 *pll_multiplier = 100; 768 break; 769 default: 770 *pll_multiplier = 66; 771 break; 772 } 773 return PHYMOD_E_NONE; 774 } 775 776 /* to modify the sub-port speed */ 777 STATIC 778 int _qtce16_qsgmii_interface_config_set(const phymod_phy_access_t* phy, uint32_t flags, const phymod_phy_inf_config_t* config) 779 { 780 qmod16_spd_intfc_type spd_intf = QMOD16_SPD_ILLEGAL; 781 qmod16_spd_intfc_type qmod16_spd_intf = QMOD16_SPD_ILLEGAL, base_spd_intf; 782 phymod_phy_access_t pm_phy_copy; 783 int start_lane, lane_id, sub_port, num_lane ; 784 785 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 786 787 /* next program the tx fir taps and driver current based on the input */ 788 /* get num_lane only in QTC */ 789 PHYMOD_IF_ERR_RETURN 790 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 791 792 PHYMOD_IF_ERR_RETURN 793 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 794 795 start_lane = lane_id ; 796 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 797 798 spd_intf = QMOD16_SPD_1000_SGMII; /* to prevent undefinded QMOD16_SPD_ILLEGAL accessing tables */ 799 800 switch(config->data_rate) { 801 case 10: 802 spd_intf = QMOD16_SPD_10_SGMII; 803 break; 804 case 100: 805 spd_intf = QMOD16_SPD_100_SGMII; 806 break; 807 case 1000: 808 spd_intf = QMOD16_SPD_1000_SGMII; 809 break; 810 case 2500: 811 spd_intf = QMOD16_SPD_2500_USXGMII; 812 break; 813 default: 814 spd_intf = QMOD16_SPD_ILLEGAL; 815 break; 816 } 817 818 qmod16_spd_intf = spd_intf; 819 base_spd_intf = PHYMOD_ACC_F_QMODE_GET(&phy->access) ? QMOD16_SPD_1000_SGMII : QMOD16_SPD_2500_USXGMII; 820 821 /* All sub-port speed changes have to go through the base, not replicated speed */ 822 PHYMOD_IF_ERR_RETURN 823 (qmod16_set_qport_spd(&pm_phy_copy.access, sub_port, base_spd_intf)); 824 825 if (qmod16_spd_intf != base_spd_intf) { 826 PHYMOD_IF_ERR_RETURN 827 (qmod16_set_qport_spd(&pm_phy_copy.access, sub_port, qmod16_spd_intf)); 828 } 829 830 return PHYMOD_E_NONE; 831 832 } 833 834 int qtce16_phy_interface_config_set(const phymod_phy_access_t* phy, uint32_t flags, const phymod_phy_inf_config_t* config) 835 { 836 uint32_t current_pll_div=0; 837 uint32_t new_pll_div=0; 838 uint16_t new_speed_vec=0; 839 qmod16_spd_intfc_type spd_intf = QMOD16_SPD_ILLEGAL; 840 phymod_phy_access_t pm_phy_copy; 841 int start_lane, num_lane, i; 842 int lane_id, sub_port ; 843 uint32_t sc_enable = 0; 844 uint32_t u_os_mode = 0; 845 phymod_firmware_lane_config_t firmware_lane_config; 846 847 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 848 849 firmware_lane_config.MediaType = phymodFirmwareMediaTypePcbTraceBackPlane; /* MediaType=0 */ 850 851 /* next program the tx fir taps and driver current based on the input */ 852 /* get num_lane only in QTC */ 853 PHYMOD_IF_ERR_RETURN 854 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 855 856 PHYMOD_IF_ERR_RETURN 857 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 858 859 start_lane = lane_id ; 860 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 861 862 /* Set subport speed if the lane speed is configured in QSGMII/USXGMII mode */ 863 if (PHYMOD_ACC_F_QMODE_GET(&phy->access) || PHYMOD_ACC_F_USXMODE_GET(&phy->access)) { 864 qmod16_speedchange_get(&pm_phy_copy.access, &sc_enable) ; 865 if (sc_enable) { 866 return _qtce16_qsgmii_interface_config_set(phy, flags, config); 867 } 868 } 869 870 PHYMOD_IF_ERR_RETURN 871 (qmod16_reset(&pm_phy_copy.access)); 872 873 /* Hold the per lane soft reset bit */ 874 for (i = 0; i < num_lane; i++) { 875 pm_phy_copy.access.lane_mask = 1 << (start_lane + i); 876 PHYMOD_IF_ERR_RETURN 877 (merlin16_lane_soft_reset_release(&pm_phy_copy.access, 0)); 878 } 879 880 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 881 PHYMOD_IF_ERR_RETURN 882 (qtce16_phy_firmware_lane_config_get(&pm_phy_copy, &firmware_lane_config)); 883 884 /* make sure that an and config from pcs is off */ 885 firmware_lane_config.AnEnabled = 0; 886 firmware_lane_config.LaneConfigFromPCS = 0; 887 if (PHYMOD_INTF_MODES_FIBER_GET(config)) { 888 firmware_lane_config.MediaType = phymodFirmwareMediaTypeOptics; 889 } 890 891 if (config->data_rate == 10 || config->data_rate == 100 || config->data_rate == 1000) { 892 if (config->interface_type == phymodInterfaceSGMII) { 893 firmware_lane_config.MediaType = phymodFirmwareMediaTypePcbTraceBackPlane; 894 } 895 if (config->interface_type == phymodInterface1000X) { 896 firmware_lane_config.MediaType = phymodFirmwareMediaTypeOptics; 897 } 898 } else if (config->data_rate == 2500) { 899 if (config->interface_type == phymodInterfaceSGMII) { 900 firmware_lane_config.MediaType = phymodFirmwareMediaTypePcbTraceBackPlane; 901 firmware_lane_config.DfeOn = 1; 902 firmware_lane_config.Cl72RestTO = 1; 903 } else { 904 firmware_lane_config.MediaType = phymodFirmwareMediaTypeOptics; 905 } 906 } 907 908 switch (config->data_rate) { 909 case 10: 910 spd_intf = QMOD16_SPD_10_X1_10; 911 break; 912 case 100: 913 spd_intf = QMOD16_SPD_100_X1_10; 914 break; 915 case 1000: 916 spd_intf = QMOD16_SPD_1000_X1_10; 917 break; 918 default: 919 spd_intf = QMOD16_SPD_ILLEGAL; 920 break; 921 } 922 923 if (PHYMOD_ACC_F_QMODE_GET(&phy->access)) { 924 spd_intf = QMOD16_SPD_4000; 925 } else if (PHYMOD_ACC_F_USXMODE_GET(&phy->access)) { 926 spd_intf = QMOD16_SPD_10G_X1_USXGMII; 927 } 928 929 PHYMOD_IF_ERR_RETURN 930 (qmod16_get_plldiv(&pm_phy_copy.access, ¤t_pll_div)); 931 932 PHYMOD_IF_ERR_RETURN 933 (qmod16_plldiv_lkup_get(&pm_phy_copy.access, spd_intf, &new_pll_div, &new_speed_vec)); 934 935 PHYMOD_IF_ERR_RETURN 936 (qmod16_pmd_osmode_set(&pm_phy_copy.access, spd_intf, u_os_mode)); 937 938 /* Don't support PLL change because 10.3125G is for USXGMII and 10G for QSGMII/SGMII/GMII.*/ 939 if (current_pll_div != new_pll_div) { 940 PHYMOD_RETURN_WITH_ERR(PHYMOD_E_CONFIG, 941 (_PHYMOD_MSG("Not support VCO change: %u %u\r\n"), 942 current_pll_div, new_pll_div)); 943 } 944 945 for (i = 0; i < num_lane; i++) { 946 pm_phy_copy.access.lane_mask = 0x1 << (start_lane + i); 947 PHYMOD_IF_ERR_RETURN 948 (_qtce16_phy_firmware_lane_config_set(&pm_phy_copy, firmware_lane_config)); 949 } 950 951 /* Release the per lane soft reset bit */ 952 for (i = 0; i < num_lane; i++) { 953 pm_phy_copy.access.lane_mask = 1 << (start_lane + i); 954 PHYMOD_IF_ERR_RETURN 955 (merlin16_lane_soft_reset_release(&pm_phy_copy.access, 1)); 956 } 957 958 /* Set lane speed ID and trigger speed change */ 959 PHYMOD_IF_ERR_RETURN 960 (qmod16_set_spd_intf(&pm_phy_copy.access, spd_intf, 0)); 961 962 /* Set sub-port speed of this lane */ 963 if (PHYMOD_ACC_F_QMODE_GET(&phy->access) || PHYMOD_ACC_F_USXMODE_GET(&phy->access)) { 964 PHYMOD_IF_ERR_RETURN 965 (_qtce16_qsgmii_interface_config_set(phy, flags, config)); 966 } 967 968 969 return PHYMOD_E_NONE; 970 } 971 972 int _qtce16_speed_id_interface_config_get(const phymod_phy_access_t* phy, int speed_id, 973 phymod_phy_inf_config_t* config, uint16_t an_enable, 974 phymod_firmware_lane_config_t *lane_config) 975 { 976 int ilkn_set; 977 int osr_mode; 978 uint32_t vco_rate; 979 uint32_t pll_multiplier; 980 uint32_t current_pll_div=0; 981 uint32_t actual_osr, actual_osr_rem; 982 phymod_osr_mode_t osr_mode_enum; 983 984 PHYMOD_IF_ERR_RETURN 985 (qmod16_get_plldiv(&phy->access, ¤t_pll_div)); 986 987 ilkn_set = 0; 988 /* coverity[dead_error_condition] */ 989 if(ilkn_set) { 990 /* coverity[dead_error_begin] */ 991 config->interface_type = phymodInterfaceBypass; 992 PHYMOD_IF_ERR_RETURN 993 (_qtce16_pll_multiplier_get(current_pll_div, &pll_multiplier)); 994 PHYMOD_IF_ERR_RETURN 995 (merlin16_osr_mode_get(&phy->access, &osr_mode)); 996 997 switch (config->ref_clock) { 998 case phymodRefClk156Mhz: 999 vco_rate = pll_multiplier * 156 + pll_multiplier * 25 / 100; 1000 break; 1001 case phymodRefClk125Mhz: 1002 vco_rate = pll_multiplier * 125; 1003 break; 1004 default: 1005 vco_rate = pll_multiplier * 156 + pll_multiplier * 25 / 100; 1006 break; 1007 } 1008 1009 PHYMOD_IF_ERR_RETURN(merlin16_osr_mode_to_enum(osr_mode, &osr_mode_enum)); 1010 PHYMOD_IF_ERR_RETURN(phymod_osr_mode_to_actual_os(osr_mode_enum, &actual_osr, &actual_osr_rem)); 1011 config->data_rate = vco_rate/actual_osr; 1012 } else { 1013 switch (speed_id) { 1014 case 0x1: 1015 config->data_rate = 10; 1016 config->interface_type = phymodInterfaceSGMII; 1017 break; 1018 case 0x2: 1019 config->data_rate = 100; 1020 config->interface_type = phymodInterfaceSGMII; 1021 break; 1022 case 0x3: 1023 if (lane_config->MediaType == phymodFirmwareMediaTypeOptics) { 1024 config->interface_type = phymodInterface1000X; 1025 } else { 1026 config->interface_type = phymodInterfaceSGMII; 1027 } 1028 config->data_rate = 1000; 1029 break; 1030 case 0x5: 1031 config->data_rate = 1000; 1032 config->interface_type = phymodInterfaceKX; 1033 break; 1034 case 0x6: 1035 config->data_rate = 2500; 1036 if (lane_config->MediaType == phymodFirmwareMediaTypeOptics) { 1037 config->interface_type = phymodInterfaceSR; 1038 } else { 1039 config->interface_type = phymodInterfaceSGMII; 1040 } 1041 break; 1042 case 0x39: 1043 config->data_rate = 10; 1044 config->interface_type = phymodInterfaceSGMII; 1045 break; 1046 case 0x3a: 1047 config->data_rate = 100; 1048 config->interface_type = phymodInterfaceSGMII; 1049 break; 1050 case 0x3b: 1051 config->data_rate = 1000; 1052 config->interface_type = phymodInterfaceSGMII; 1053 break; 1054 case 0x3c: /* this is qsgmii mode */ 1055 config->data_rate = 1000; 1056 config->interface_type = phymodInterfaceSGMII; 1057 break; 1058 case 0x48: 1059 config->data_rate = 2500; 1060 config->interface_type = phymodInterfaceSGMII; 1061 break; 1062 default: 1063 config->data_rate = 0; 1064 config->interface_type = phymodInterfaceSGMII; 1065 break; 1066 } 1067 } 1068 return PHYMOD_E_NONE; 1069 } 1070 1071 int qtce16_phy_interface_config_get(const phymod_phy_access_t* phy, uint32_t flags, phymod_ref_clk_t ref_clock, phymod_phy_inf_config_t* config) 1072 { 1073 int speed_id; 1074 phymod_firmware_lane_config_t firmware_lane_config; 1075 phymod_phy_access_t pm_phy_copy; 1076 int start_lane, num_lane; 1077 qmod16_an_control_t an_control; 1078 qmod16_an_ability_t an_ability_st; 1079 int an_complete = 0; 1080 int lane_id, sub_port ; 1081 1082 config->ref_clock = ref_clock; 1083 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 1084 PHYMOD_IF_ERR_RETURN 1085 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 1086 1087 PHYMOD_IF_ERR_RETURN 1088 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1089 start_lane = lane_id ; 1090 1091 pm_phy_copy.access.lane_mask = 0x1 << start_lane; 1092 PHYMOD_IF_ERR_RETURN 1093 (qmod16_speed_id_get(&pm_phy_copy.access, &speed_id, sub_port)); 1094 1095 PHYMOD_MEMSET(&an_control, 0x0, sizeof(qmod16_an_control_t)); 1096 PHYMOD_IF_ERR_RETURN 1097 (qmod16_autoneg_control_get(&pm_phy_copy.access, sub_port, &an_control, &an_complete)); 1098 1099 /* There is no resolved speed ID register for USXGMII. Get it from AN resolution HCD if AN is enabled */ 1100 if (PHYMOD_ACC_F_USXMODE_GET(&phy->access) && an_control.enable && an_complete) { 1101 PHYMOD_MEMSET(&an_ability_st, 0x0, sizeof(qmod16_an_ability_t)); 1102 PHYMOD_IF_ERR_RETURN 1103 (qmod16_autoneg_resolution_ability_get(&pm_phy_copy.access, &an_ability_st, sub_port)); 1104 1105 speed_id = an_ability_st.cl37_adv.cl37_sgmii_speed; 1106 } 1107 1108 PHYMOD_IF_ERR_RETURN 1109 (qtce16_phy_firmware_lane_config_get(phy, &firmware_lane_config)); 1110 1111 PHYMOD_IF_ERR_RETURN 1112 (_qtce16_speed_id_interface_config_get(&pm_phy_copy, speed_id, config, an_control.enable, &firmware_lane_config)); 1113 1114 if (firmware_lane_config.MediaType == phymodFirmwareMediaTypeOptics) { 1115 PHYMOD_INTF_MODES_FIBER_SET(config); 1116 } else { 1117 PHYMOD_INTF_MODES_FIBER_CLR(config); 1118 } 1119 1120 return PHYMOD_E_NONE; 1121 1122 } 1123 1124 int qtce16_phy_autoneg_ability_set(const phymod_phy_access_t* phy, const phymod_autoneg_ability_t* an_ability) 1125 { 1126 qmod16_an_ability_t value; 1127 int start_lane, num_lane; 1128 phymod_phy_access_t phy_copy; 1129 int lane_id, sub_port ; 1130 1131 /* next program the tx fir taps and driver current based on the input */ 1132 PHYMOD_IF_ERR_RETURN 1133 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 1134 1135 PHYMOD_IF_ERR_RETURN 1136 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1137 1138 start_lane = lane_id ; 1139 1140 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1141 phy_copy.access.lane_mask = 0x1 << start_lane; 1142 1143 PHYMOD_MEMSET(&value, 0x0, sizeof(value)); 1144 1145 /* check if sgmii or not */ 1146 if (PHYMOD_AN_CAP_SGMII_GET(an_ability)) { 1147 switch (an_ability->sgmii_speed) { 1148 case phymod_CL37_SGMII_10M: 1149 value.cl37_adv.cl37_sgmii_speed = QMOD16_CL37_SGMII_10M; 1150 break; 1151 case phymod_CL37_SGMII_100M: 1152 value.cl37_adv.cl37_sgmii_speed = QMOD16_CL37_SGMII_100M; 1153 break; 1154 case phymod_CL37_SGMII_1000M: 1155 value.cl37_adv.cl37_sgmii_speed = QMOD16_CL37_SGMII_1000M; 1156 break; 1157 case phymod_CL37_SGMII_2500M: 1158 value.cl37_adv.cl37_sgmii_speed = QMOD16_CL37_SGMII_2500M; 1159 break; 1160 default: 1161 value.cl37_adv.cl37_sgmii_speed = QMOD16_CL37_SGMII_1000M; 1162 break; 1163 } 1164 if( PHYMOD_AN_CAP_HALF_DUPLEX_GET(an_ability)) { 1165 value.cl37_adv.an_duplex = QMOD16_AN_HALF_DUPLEX_SET ; 1166 } 1167 } 1168 /* next check pause */ 1169 if (PHYMOD_AN_CAP_SYMM_PAUSE_GET(an_ability) && !PHYMOD_AN_CAP_ASYM_PAUSE_GET(an_ability)) { 1170 value.cl37_adv.an_pause = QMOD16_SYMM_PAUSE; 1171 } 1172 if (PHYMOD_AN_CAP_ASYM_PAUSE_GET(an_ability) && !PHYMOD_AN_CAP_SYMM_PAUSE_GET(an_ability)) { 1173 value.cl37_adv.an_pause = QMOD16_ASYM_PAUSE; 1174 } 1175 if (PHYMOD_AN_CAP_ASYM_PAUSE_GET(an_ability) && PHYMOD_AN_CAP_SYMM_PAUSE_GET(an_ability)) { 1176 value.cl37_adv.an_pause = QMOD16_ASYM_SYMM_PAUSE; 1177 } 1178 1179 /* check cl37 and cl37 bam ability */ 1180 if (PHYMOD_AN_CAP_CL37BAM_GET(an_ability)) { 1181 value.cl37_adv.an_bam_speed |= 1 << QMOD16_CL37_BAM_2p5GBASE_X; 1182 PHYMOD_IF_ERR_RETURN 1183 (qmod16_an_cl37_bam_abilities(&phy_copy.access, &value, sub_port)); 1184 } else { 1185 PHYMOD_IF_ERR_RETURN 1186 (qmod16_autoneg_cl37_base_abilities(&phy_copy.access, &value, sub_port)); 1187 } 1188 1189 return PHYMOD_E_NONE; 1190 1191 } 1192 1193 int qtce16_phy_autoneg_ability_get(const phymod_phy_access_t* phy, phymod_autoneg_ability_t* an_ability_get_type) 1194 { 1195 qmod16_an_ability_t value; 1196 phymod_phy_access_t phy_copy; 1197 int lane_id, sub_port ; 1198 1199 1200 PHYMOD_IF_ERR_RETURN 1201 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1202 1203 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1204 phy_copy.access.lane_mask = 0x1 << lane_id; 1205 PHYMOD_MEMSET(&value, 0x0, sizeof(value)); 1206 1207 PHYMOD_IF_ERR_RETURN 1208 (qmod16_autoneg_local_ability_get(&phy_copy.access, &value, sub_port)); 1209 1210 if(value.cl37_adv.an_type != QMOD16_AN_MODE_NONE) { 1211 if (value.cl37_adv.an_pause == QMOD16_ASYM_PAUSE) { 1212 PHYMOD_AN_CAP_ASYM_PAUSE_SET(an_ability_get_type); 1213 } else if (value.cl37_adv.an_pause == QMOD16_SYMM_PAUSE) { 1214 PHYMOD_AN_CAP_SYMM_PAUSE_SET(an_ability_get_type); 1215 } else if (value.cl37_adv.an_pause == QMOD16_ASYM_SYMM_PAUSE) { 1216 PHYMOD_AN_CAP_ASYM_PAUSE_SET(an_ability_get_type); 1217 PHYMOD_AN_CAP_SYMM_PAUSE_SET(an_ability_get_type); 1218 } 1219 if(value.cl37_adv.an_type & QMOD16_AN_MODE_CL37) { 1220 PHYMOD_AN_CAP_CL37_SET(an_ability_get_type) ; 1221 PHYMOD_AN_CAP_HALF_DUPLEX_CLR(an_ability_get_type) ; 1222 } 1223 if(value.cl37_adv.an_type & QMOD16_AN_MODE_SGMII) { 1224 PHYMOD_AN_CAP_SGMII_SET(an_ability_get_type) ; 1225 /* get the cl37 sgmii speed */ 1226 switch (value.cl37_adv.cl37_sgmii_speed) { 1227 case QMOD16_CL37_SGMII_10M: 1228 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_10M; 1229 break; 1230 case QMOD16_CL37_SGMII_100M: 1231 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_100M; 1232 break; 1233 case QMOD16_CL37_SGMII_1000M: 1234 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_1000M; 1235 break; 1236 case QMOD16_CL37_SGMII_2500M: 1237 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_2500M; 1238 break; 1239 default: 1240 break; 1241 } 1242 if(value.cl37_adv.an_duplex & QMOD16_AN_HALF_DUPLEX_SET ) { 1243 PHYMOD_AN_CAP_HALF_DUPLEX_SET(an_ability_get_type) ; 1244 } else { 1245 PHYMOD_AN_CAP_HALF_DUPLEX_CLR(an_ability_get_type) ; 1246 } 1247 } 1248 if(value.cl37_adv.an_type & QMOD16_AN_MODE_CL37BAM) { 1249 /* check cl37 bam ability */ 1250 if (value.cl37_adv.an_bam_speed & 1 << QMOD16_CL37_BAM_2p5GBASE_X) 1251 PHYMOD_BAM_CL37_CAP_2P5G_SET(an_ability_get_type->cl37bam_cap); 1252 } 1253 } 1254 return PHYMOD_E_NONE; 1255 1256 } 1257 1258 1259 int qtce16_phy_autoneg_remote_ability_get(const phymod_phy_access_t* phy, phymod_autoneg_ability_t* an_ability_get_type) 1260 { 1261 1262 qmod16_an_ability_t value; 1263 phymod_phy_access_t phy_copy; 1264 int lane_id, sub_port ; 1265 1266 1267 PHYMOD_IF_ERR_RETURN 1268 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1269 1270 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1271 phy_copy.access.lane_mask = 0x1 << lane_id; 1272 PHYMOD_MEMSET(&value, 0x0, sizeof(value)); 1273 1274 PHYMOD_IF_ERR_RETURN 1275 (qmod16_autoneg_remote_ability_get(&phy_copy.access, &value, sub_port)); 1276 1277 if (value.cl37_adv.an_pause == QMOD16_ASYM_PAUSE) { 1278 PHYMOD_AN_CAP_ASYM_PAUSE_SET(an_ability_get_type); 1279 } else if (value.cl37_adv.an_pause == QMOD16_SYMM_PAUSE) { 1280 PHYMOD_AN_CAP_SYMM_PAUSE_SET(an_ability_get_type); 1281 } else if (value.cl37_adv.an_pause == QMOD16_ASYM_SYMM_PAUSE) { 1282 PHYMOD_AN_CAP_ASYM_PAUSE_SET(an_ability_get_type); 1283 PHYMOD_AN_CAP_SYMM_PAUSE_SET(an_ability_get_type); 1284 } 1285 if(value.cl37_adv.an_type != QMOD16_AN_MODE_NONE) { 1286 if(value.cl37_adv.an_type & QMOD16_AN_MODE_CL37) { 1287 PHYMOD_AN_CAP_CL37_SET(an_ability_get_type) ; 1288 PHYMOD_AN_CAP_HALF_DUPLEX_CLR(an_ability_get_type) ; 1289 } 1290 if(value.cl37_adv.an_type & QMOD16_AN_MODE_SGMII) { 1291 PHYMOD_AN_CAP_SGMII_SET(an_ability_get_type) ; 1292 /* get the cl37 sgmii speed */ 1293 switch (value.cl37_adv.cl37_sgmii_speed) { 1294 case QMOD16_CL37_SGMII_10M: 1295 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_10M; 1296 break; 1297 case QMOD16_CL37_SGMII_100M: 1298 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_100M; 1299 break; 1300 case QMOD16_CL37_SGMII_1000M: 1301 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_1000M; 1302 break; 1303 case QMOD16_CL37_SGMII_2500M: 1304 an_ability_get_type->sgmii_speed = phymod_CL37_SGMII_2500M; 1305 break; 1306 default: 1307 break; 1308 } 1309 } 1310 /* check cl37 bam ability */ 1311 if (value.cl37_adv.an_bam_speed & 1 << QMOD16_CL37_BAM_2p5GBASE_X) 1312 PHYMOD_BAM_CL37_CAP_2P5G_SET(an_ability_get_type->cl37bam_cap); 1313 } 1314 1315 return PHYMOD_E_NONE; 1316 1317 } 1318 1319 STATIC 1320 int _qtce16_qsgmii_autoneg_set(const phymod_phy_access_t* phy, const phymod_autoneg_control_t* an) 1321 { 1322 int num_lane_adv_encoded; 1323 int start_lane, num_lane, lane_id, sub_port; 1324 phymod_phy_access_t phy_copy; 1325 qmod16_an_control_t an_control; 1326 1327 1328 /* next program the tx fir taps and driver current based on the input */ 1329 PHYMOD_IF_ERR_RETURN 1330 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 1331 1332 PHYMOD_IF_ERR_RETURN 1333 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1334 1335 start_lane = lane_id ; 1336 1337 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1338 phy_copy.access.lane_mask = 0x1 << start_lane; 1339 1340 num_lane_adv_encoded = 0; /* one lane */ 1341 an_control.pd_kx4_en = 0; /* for now disable */ 1342 an_control.pd_kx_en = 0; /* for now disable */ 1343 an_control.num_lane_adv = num_lane_adv_encoded; 1344 an_control.enable = an->enable; 1345 an_control.an_property_type = 0x0; /* for now disable */ 1346 an_control.an_type = QMOD16_AN_MODE_SGMII; 1347 1348 phy_copy.access.lane_mask = 0x1 << start_lane; 1349 1350 PHYMOD_IF_ERR_RETURN 1351 (qmod16_autoneg_control(&phy_copy.access, &an_control, sub_port)); 1352 1353 return PHYMOD_E_NONE; 1354 1355 } 1356 1357 int qtce16_phy_autoneg_set(const phymod_phy_access_t* phy, const phymod_autoneg_control_t* an) 1358 { 1359 phymod_firmware_lane_config_t firmware_lane_config; 1360 int start_lane, num_lane, i, lane_id, sub_port; 1361 phymod_phy_access_t phy_copy; 1362 qmod16_an_control_t an_control; 1363 1364 /* QTCE16 doesn't support 10G KX4 and 1G KX parallel detection */ 1365 if (PHYMOD_AN_F_SET_CL73_PDET_KX4_ENABLE_GET(an) || 1366 PHYMOD_AN_F_SET_CL73_PDET_KX_ENABLE_GET(an)) { 1367 return PHYMOD_E_UNAVAIL; 1368 } 1369 1370 if (PHYMOD_ACC_F_QMODE_GET(&phy->access) || PHYMOD_ACC_F_USXMODE_GET(&phy->access)) { 1371 return _qtce16_qsgmii_autoneg_set(phy, an); 1372 } 1373 1374 /* next program the tx fir taps and driver current based on the input */ 1375 PHYMOD_IF_ERR_RETURN 1376 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 1377 1378 PHYMOD_IF_ERR_RETURN 1379 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1380 1381 start_lane = lane_id ; 1382 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1383 phy_copy.access.lane_mask = 0x1 << start_lane; 1384 1385 an_control.pd_kx4_en = 0; /* for now disable */ 1386 an_control.pd_kx_en = 0; /* for now disable */ 1387 an_control.num_lane_adv = 0; 1388 an_control.enable = an->enable; 1389 an_control.an_property_type = 0x0; /* for now disable */ 1390 switch (an->an_mode) { 1391 case phymod_AN_MODE_CL37: 1392 an_control.an_type = QMOD16_AN_MODE_CL37; 1393 break; 1394 case phymod_AN_MODE_CL37BAM: 1395 { 1396 an_control.an_type = QMOD16_AN_MODE_CL37BAM; 1397 break; 1398 } 1399 case phymod_AN_MODE_SGMII: 1400 an_control.an_type = QMOD16_AN_MODE_SGMII; 1401 break; 1402 default: 1403 an_control.an_type = QMOD16_AN_MODE_CL37; 1404 break; 1405 } 1406 1407 /* put pcs into reset */ 1408 PHYMOD_IF_ERR_RETURN 1409 (qmod16_reset(&phy_copy.access)); 1410 1411 for (i = 0; i < num_lane; i++) { 1412 phy_copy.access.lane_mask = 0x1 << (i + start_lane); 1413 PHYMOD_IF_ERR_RETURN 1414 (merlin16_lane_soft_reset_release(&phy_copy.access, 0)); 1415 } 1416 1417 /* make sure the firmware config is set to an eenabled */ 1418 PHYMOD_IF_ERR_RETURN 1419 (qtce16_phy_firmware_lane_config_get(phy, &firmware_lane_config)); 1420 if (an->enable) { 1421 firmware_lane_config.AnEnabled = 1; 1422 firmware_lane_config.LaneConfigFromPCS = 1; 1423 } else { 1424 firmware_lane_config.AnEnabled = 0; 1425 firmware_lane_config.LaneConfigFromPCS = 0; 1426 } 1427 1428 for (i = 0; i < num_lane; i++) { 1429 phy_copy.access.lane_mask = 0x1 << (i + start_lane); 1430 PHYMOD_IF_ERR_RETURN 1431 (_qtce16_phy_firmware_lane_config_set(&phy_copy, firmware_lane_config)); 1432 } 1433 1434 for (i = 0; i < num_lane; i++) { 1435 phy_copy.access.lane_mask = 0x1 << (i + start_lane); 1436 PHYMOD_IF_ERR_RETURN 1437 (merlin16_lane_soft_reset_release(&phy_copy.access, 1)); 1438 } 1439 1440 if (!an->enable) { /* would SGMII AN exception */ 1441 PHYMOD_IF_ERR_RETURN 1442 (qmod16_trigger_speed_change(&phy_copy.access)); 1443 } 1444 1445 phy_copy.access.lane_mask = 0x1 << start_lane; 1446 PHYMOD_IF_ERR_RETURN 1447 (qmod16_autoneg_control(&phy_copy.access, &an_control, sub_port)); 1448 1449 1450 return PHYMOD_E_NONE; 1451 1452 } 1453 1454 int qtce16_phy_autoneg_get(const phymod_phy_access_t* phy, phymod_autoneg_control_t* an, uint32_t* an_done) 1455 { 1456 1457 qmod16_an_control_t an_control; 1458 phymod_phy_access_t phy_copy; 1459 int start_lane, num_lane, lane_id, sub_port; 1460 int an_complete = 0; 1461 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1462 1463 PHYMOD_IF_ERR_RETURN 1464 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 1465 1466 PHYMOD_IF_ERR_RETURN 1467 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1468 1469 start_lane = lane_id ; 1470 phy_copy.access.lane_mask = 0x1 << start_lane; 1471 1472 PHYMOD_MEMSET(&an_control, 0x0, sizeof(qmod16_an_control_t)); 1473 PHYMOD_IF_ERR_RETURN 1474 (qmod16_autoneg_control_get(&phy_copy.access, sub_port, &an_control, &an_complete)); 1475 1476 if (an_control.enable) { 1477 an->enable = 1; 1478 if (an_control.an_type == QMOD16_AN_MODE_CL37) { 1479 an->an_mode = phymod_AN_MODE_CL37; 1480 } else if (an_control.an_type == QMOD16_AN_MODE_CL37BAM) { 1481 an->an_mode = phymod_AN_MODE_CL37BAM; 1482 } else { 1483 an->an_mode = phymod_AN_MODE_SGMII; 1484 } 1485 *an_done = an_complete; 1486 } else { 1487 an->enable = 0; 1488 } 1489 1490 /* QTCE16 doesn't support 10G KX4 and 1G KX parallel detection */ 1491 PHYMOD_AN_F_SET_CL73_PDET_KX_ENABLE_CLR(an); 1492 PHYMOD_AN_F_SET_CL73_PDET_KX4_ENABLE_CLR(an); 1493 1494 1495 return PHYMOD_E_NONE; 1496 1497 } 1498 1499 1500 int qtce16_phy_autoneg_status_get(const phymod_phy_access_t* phy, phymod_autoneg_status_t* status) 1501 { 1502 1503 return PHYMOD_E_NONE; 1504 1505 } 1506 1507 1508 int qtce16_core_init(const phymod_core_access_t* core, const phymod_core_init_config_t* init_config, const phymod_core_status_t* core_status) 1509 { 1510 phymod_phy_access_t phy_access, phy_access_copy; 1511 phymod_core_access_t core_copy; 1512 phymod_firmware_core_config_t firmware_core_config_tmp; 1513 uint32_t uc_active = 0; 1514 int i, num_lane, start_lane; 1515 1516 1517 PHYMOD_MEMCPY(&core_copy, core, sizeof(core_copy)); 1518 core_copy.access.lane_mask = 0x1; 1519 1520 PHYMOD_IF_ERR_RETURN(phymod_phy_access_t_init(&phy_access)); 1521 QTCE16_CORE_TO_PHY_ACCESS(&phy_access, core); 1522 PHYMOD_MEMCPY(&phy_access_copy, &phy_access, sizeof(phy_access_copy)); 1523 phy_access_copy.access.lane_mask = 0x1; 1524 1525 PHYMOD_IF_ERR_RETURN 1526 (qmod16_pmd_reset_seq(&core_copy.access, core_status->pmd_active)); 1527 1528 PHYMOD_IF_ERR_RETURN 1529 (phymod_util_lane_config_get(&phy_access.access, &start_lane, &num_lane)); 1530 1531 /* 1532 * Before programming the PMD lane address map register, the PMD lanes 1533 * have to be reset. Without do this, writing the PMD lane address map 1534 * regsiter will not take effect, meaning the reading value != writing 1535 * value. 1536 */ 1537 for (i = 0; i < QTCE16_NOF_LANES_IN_CORE; i++) { 1538 phy_access.access.lane_mask = 1 << (start_lane + i); 1539 PHYMOD_IF_ERR_RETURN 1540 (qmod16_pmd_x4_reset(&phy_access.access)); 1541 } 1542 1543 PHYMOD_IF_ERR_RETURN(merlin16_uc_active_get(&core_copy.access, &uc_active)); 1544 if (uc_active) { 1545 return(PHYMOD_E_NONE); 1546 } 1547 1548 /* Propgram shim fifo threshold for USXGMII mode */ 1549 if (PHYMOD_ACC_F_USXMODE_GET(&core->access)) { 1550 PHYMOD_IF_ERR_RETURN(qmod16_usgmii_shim_fifo_threshold_set(&core_copy.access)); 1551 } 1552 1553 /* need to set the heart beat default is for 156.25M */ 1554 if (init_config->interface.ref_clock == phymodRefClk125Mhz) { 1555 PHYMOD_IF_ERR_RETURN 1556 (qmod16_refclk_set(&core_copy.access, QMOD16REFCLK125MHZ)) ; 1557 } else { 1558 PHYMOD_IF_ERR_RETURN 1559 (qmod16_refclk_set(&core_copy.access, QMOD16REFCLK156MHZ)) ; 1560 } 1561 1562 PHYMOD_IF_ERR_RETURN 1563 (qtce16_core_lane_map_set(&core_copy, &init_config->lane_map)); 1564 1565 PHYMOD_IF_ERR_RETURN 1566 (merlin16_uc_reset(&phy_access_copy.access, 1)); 1567 1568 if (_qtce16_core_firmware_load(&core_copy, init_config->firmware_load_method, init_config->firmware_loader)) { 1569 PHYMOD_DEBUG_ERROR(("devad 0x%x lane 0x%x: UC firmware-load failed\n", core->access.addr, core->access.lane_mask)); 1570 PHYMOD_IF_ERR_RETURN (PHYMOD_E_INIT); 1571 } 1572 1573 /* merlin16 programmer quide */ 1574 PHYMOD_IF_ERR_RETURN 1575 (merlin16_pmd_ln_h_rstb_pkill_override( &phy_access_copy.access, 0x1)); 1576 1577 PHYMOD_IF_ERR_RETURN 1578 (merlin16_uc_reset(&phy_access_copy.access, 0)); 1579 PHYMOD_IF_ERR_RETURN 1580 (merlin16_wait_uc_active(&phy_access_copy.access)); 1581 1582 /* Initialize software information table for the micro */ 1583 PHYMOD_IF_ERR_RETURN 1584 (merlin16_init_merlin16_info(&core_copy.access)); 1585 1586 if (init_config->firmware_load_method != phymodFirmwareLoadMethodNone) { 1587 if (PHYMOD_CORE_INIT_F_FIRMWARE_LOAD_VERIFY_GET(init_config)) { 1588 PHYMOD_IF_ERR_RETURN 1589 (merlin16_start_ucode_crc_calc(&core_copy.access, merlin16_ucode_len)); 1590 } 1591 } 1592 1593 if (init_config->firmware_load_method != phymodFirmwareLoadMethodNone) { 1594 if (PHYMOD_CORE_INIT_F_FIRMWARE_LOAD_VERIFY_GET(init_config)) { 1595 PHYMOD_IF_ERR_RETURN 1596 (merlin16_check_ucode_crc(&core_copy.access, merlin16_ucode_crc, 250)); 1597 } 1598 } 1599 1600 PHYMOD_IF_ERR_RETURN( 1601 merlin16_pmd_ln_h_rstb_pkill_override( &phy_access_copy.access, 0x0)); 1602 1603 PHYMOD_IF_ERR_RETURN 1604 (merlin16_core_soft_reset_release(&core_copy.access, 0)); 1605 1606 /* plldiv CONFIG */ 1607 if (PHYMOD_ACC_F_USXMODE_GET(&core->access)) { 1608 PHYMOD_IF_ERR_RETURN 1609 (merlin16_configure_pll_refclk_div(&core_copy.access, MERLIN16_PLL_REFCLK_156P25MHZ, MERLIN16_PLL_DIV_66)); 1610 } else { 1611 PHYMOD_IF_ERR_RETURN 1612 (merlin16_configure_pll_refclk_div(&core_copy.access, MERLIN16_PLL_REFCLK_156P25MHZ, MERLIN16_PLL_DIV_64)); 1613 } 1614 1615 PHYMOD_IF_ERR_RETURN 1616 (qmod16_autoneg_timer_init(&core_copy.access)); 1617 PHYMOD_IF_ERR_RETURN 1618 (qmod16_master_port_num_set(&core_copy.access, 0)); 1619 1620 /* don't overide the fw that set in config set if not specified */ 1621 PHYMOD_IF_ERR_RETURN 1622 (qtce16_phy_firmware_core_config_get(&phy_access_copy, &firmware_core_config_tmp)); 1623 firmware_core_config_tmp.CoreConfigFromPCS = 0; 1624 PHYMOD_IF_ERR_RETURN 1625 (qtce16_phy_firmware_core_config_set(&phy_access_copy, firmware_core_config_tmp)); 1626 1627 /* release core soft reset */ 1628 PHYMOD_IF_ERR_RETURN 1629 (merlin16_core_soft_reset_release(&core_copy.access, 1)); 1630 1631 return PHYMOD_E_NONE; 1632 1633 } 1634 1635 1636 int qtce16_phy_pll_multiplier_get(const phymod_phy_access_t* phy, uint32_t* core_vco_pll_multiplier) 1637 { 1638 1639 /* Place your code here */ 1640 1641 1642 return PHYMOD_E_NONE; 1643 1644 } 1645 1646 1647 int qtce16_phy_init(const phymod_phy_access_t* phy, const phymod_phy_init_config_t* init_config) 1648 { 1649 const phymod_access_t *pm_acc = &phy->access; 1650 phymod_phy_access_t pm_phy_copy; 1651 int start_lane, num_lane, i, lane_id, sub_port; 1652 uint32_t sc_enable = 0; 1653 phymod_polarity_t tmp_pol; 1654 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 1655 PHYMOD_MEMSET(&tmp_pol, 0x0, sizeof(tmp_pol)); 1656 1657 /* next program the tx fir taps and driver current based on the input */ 1658 PHYMOD_IF_ERR_RETURN 1659 (phymod_util_lane_config_get(pm_acc, &start_lane, &num_lane)); 1660 PHYMOD_IF_ERR_RETURN 1661 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1662 1663 start_lane = lane_id ; 1664 pm_phy_copy.access.lane_mask = 1 << start_lane; 1665 1666 if (PHYMOD_ACC_F_QMODE_GET(&phy->access) || PHYMOD_ACC_F_USXMODE_GET(&phy->access)) { 1667 PHYMOD_IF_ERR_RETURN(qmod16_port_state_set(&pm_phy_copy.access, QMOD16_PORT_STATE_CONFIGED, sub_port, 1)); 1668 PHYMOD_IF_ERR_RETURN(qmod16_speedchange_get(&pm_phy_copy.access, &sc_enable)) ; 1669 /* this lane has been initialized */ 1670 if (sc_enable) { 1671 return PHYMOD_E_NONE; 1672 } 1673 } 1674 1675 /* per lane based reset release */ 1676 PHYMOD_IF_ERR_RETURN 1677 (qmod16_pmd_x4_reset(&pm_phy_copy.access)); 1678 1679 /* poll for per lane uc_dsc_ready */ 1680 for (i = 0; i < num_lane; i++) { 1681 pm_phy_copy.access.lane_mask = 1 << (start_lane + i); 1682 PHYMOD_IF_ERR_RETURN 1683 (merlin16_lane_soft_reset_release(&pm_phy_copy.access, 1)); 1684 } 1685 1686 /* program the rx/tx polarity */ 1687 tmp_pol.tx_polarity = (init_config->polarity.tx_polarity) & 0x1; 1688 tmp_pol.rx_polarity = (init_config->polarity.rx_polarity) & 0x1; 1689 PHYMOD_IF_ERR_RETURN(qtce16_phy_polarity_set(phy, &tmp_pol)); 1690 1691 /* configure TX parameters */ 1692 PHYMOD_IF_ERR_RETURN 1693 (qtce16_phy_tx_set(phy, &init_config->tx[0])); 1694 1695 pm_phy_copy.access.lane_mask = 1 << start_lane; 1696 PHYMOD_IF_ERR_RETURN 1697 (qmod16_rx_lane_control_set(&pm_phy_copy.access, TRUE)); 1698 PHYMOD_IF_ERR_RETURN 1699 (qmod16_tx_lane_control_set(&pm_phy_copy.access, QMOD16_TX_LANE_RESET_TRAFFIC_ENABLE)); /* TX_LANE_CONTROL */ 1700 1701 return PHYMOD_E_NONE; 1702 1703 } 1704 1705 1706 int qtce16_phy_loopback_set(const phymod_phy_access_t* phy, phymod_loopback_mode_t loopback, uint32_t enable) 1707 { 1708 1709 int start_lane, num_lane, lane_id, sub_port; 1710 int i = 0; 1711 phymod_phy_access_t phy_copy; 1712 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1713 1714 /* next figure out the lane num and start_lane based on the input */ 1715 PHYMOD_IF_ERR_RETURN 1716 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 1717 1718 PHYMOD_IF_ERR_RETURN 1719 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1720 start_lane = lane_id ; 1721 1722 phy_copy.access.lane_mask = 0x1 << (i + start_lane); 1723 1724 1725 switch (loopback) { 1726 case phymodLoopbackGlobal : 1727 PHYMOD_IF_ERR_RETURN(qmod16_tx_loopback_control(&phy_copy.access, enable, start_lane, num_lane)); 1728 break; 1729 case phymodLoopbackGlobalPMD : 1730 PHYMOD_IF_ERR_RETURN(merlin16_pmd_loopback_set(&phy_copy.access, enable)); 1731 break; 1732 case phymodLoopbackRemotePMD : 1733 PHYMOD_IF_ERR_RETURN(merlin16_rmt_lpbk(&phy_copy.access, (uint8_t)enable)); 1734 break; 1735 case phymodLoopbackRemotePCS : 1736 PHYMOD_IF_ERR_RETURN(qmod16_rx_loopback_control(&phy_copy.access, enable, enable, enable)); 1737 break; 1738 default : 1739 break; 1740 } 1741 1742 return PHYMOD_E_NONE; 1743 1744 } 1745 1746 int qtce16_phy_loopback_get(const phymod_phy_access_t* phy, phymod_loopback_mode_t loopback, uint32_t* enable) 1747 { 1748 1749 uint32_t enable_core; 1750 int start_lane, num_lane, lane_id, sub_port; 1751 phymod_phy_access_t phy_copy; 1752 1753 *enable = 0; 1754 1755 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1756 /* next figure out the lane num and start_lane based on the input */ 1757 PHYMOD_IF_ERR_RETURN 1758 (phymod_util_lane_config_get(&phy->access, &start_lane, &num_lane)); 1759 1760 PHYMOD_IF_ERR_RETURN 1761 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1762 start_lane = lane_id ; 1763 1764 phy_copy.access.lane_mask = 0x1 << start_lane; 1765 1766 1767 switch (loopback) { 1768 case phymodLoopbackGlobal : 1769 PHYMOD_IF_ERR_RETURN(qmod16_tx_loopback_get(&phy_copy.access, &enable_core)); 1770 *enable = (enable_core >> start_lane) & 0x1; 1771 break; 1772 case phymodLoopbackGlobalPMD : 1773 PHYMOD_IF_ERR_RETURN(merlin16_pmd_loopback_get(&phy_copy.access, enable)); 1774 break; 1775 case phymodLoopbackRemotePMD : 1776 PHYMOD_IF_ERR_RETURN(merlin16_rmt_lpbk_get(&phy_copy.access, enable)); 1777 break; 1778 case phymodLoopbackRemotePCS : 1779 PHYMOD_IF_ERR_RETURN(qmod16_rx_loopback_get(&phy_copy.access, enable)); 1780 break; 1781 default : 1782 break; 1783 } 1784 return PHYMOD_E_NONE; 1785 1786 } 1787 1788 1789 int qtce16_phy_rx_pmd_locked_get(const phymod_phy_access_t* phy, uint32_t* rx_pmd_locked) 1790 { 1791 1792 int lane_id, sub_port; 1793 phymod_phy_access_t phy_copy; 1794 1795 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1796 PHYMOD_IF_ERR_RETURN 1797 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1798 phy_copy.access.lane_mask = 1 << lane_id; 1799 1800 PHYMOD_IF_ERR_RETURN(qmod16_pmd_lock_get(&phy_copy.access, rx_pmd_locked)); 1801 1802 return PHYMOD_E_NONE; 1803 1804 } 1805 1806 1807 int qtce16_phy_link_status_get(const phymod_phy_access_t* phy, uint32_t* link_status) 1808 { 1809 1810 int lane_id, sub_port; 1811 phymod_phy_access_t pm_phy_copy; 1812 1813 PHYMOD_MEMCPY(&pm_phy_copy, phy, sizeof(pm_phy_copy)); 1814 PHYMOD_IF_ERR_RETURN 1815 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1816 pm_phy_copy.access.lane_mask = 1 << lane_id; 1817 1818 PHYMOD_IF_ERR_RETURN(qmod16_get_pcs_link_status(&pm_phy_copy.access, sub_port, link_status)); 1819 1820 1821 return PHYMOD_E_NONE; 1822 1823 } 1824 1825 int qtce16_phy_reg_read(const phymod_phy_access_t* phy, uint32_t reg_addr, uint32_t* val) 1826 { 1827 int lane_id, sub_port; 1828 phymod_phy_access_t phy_copy; 1829 1830 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1831 PHYMOD_IF_ERR_RETURN 1832 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1833 phy_copy.access.lane_mask = 1 << lane_id; 1834 1835 PHYMOD_IF_ERR_RETURN(phymod_tsc_iblk_read(&phy_copy.access, reg_addr, val)); 1836 return PHYMOD_E_NONE; 1837 } 1838 1839 1840 int qtce16_phy_reg_write(const phymod_phy_access_t* phy, uint32_t reg_addr, uint32_t val) 1841 { 1842 int lane_id, sub_port; 1843 phymod_phy_access_t phy_copy; 1844 1845 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1846 PHYMOD_IF_ERR_RETURN 1847 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1848 phy_copy.access.lane_mask = 1 << lane_id; 1849 1850 PHYMOD_IF_ERR_RETURN(phymod_tsc_iblk_write(&phy_copy.access, reg_addr, val)); 1851 return PHYMOD_E_NONE; 1852 } 1853 1854 int qtce16_phy_eee_set(const phymod_phy_access_t* phy, uint32_t enable) 1855 { 1856 int lane_id, sub_port; 1857 phymod_phy_access_t phy_copy; 1858 1859 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1860 PHYMOD_IF_ERR_RETURN 1861 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1862 phy_copy.access.lane_mask = 1 << lane_id; 1863 1864 PHYMOD_IF_ERR_RETURN(qmod16_eee_control_set(&phy_copy.access, enable)); 1865 return PHYMOD_E_NONE; 1866 } 1867 1868 int qtce16_phy_eee_get(const phymod_phy_access_t* phy, uint32_t* enable) 1869 { 1870 uint32_t enable_local; 1871 int lane_id, sub_port; 1872 phymod_phy_access_t phy_copy; 1873 1874 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1875 PHYMOD_IF_ERR_RETURN 1876 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1877 phy_copy.access.lane_mask = 1 << lane_id; 1878 1879 PHYMOD_IF_ERR_RETURN(qmod16_eee_control_get(&phy_copy.access, &enable_local)); 1880 *enable = enable_local; 1881 return PHYMOD_E_NONE; 1882 } 1883 1884 int qtce16_phy_rx_ppm_get(const phymod_phy_access_t* phy, int16_t* rx_ppm) 1885 { 1886 int lane_id, sub_port; 1887 phymod_phy_access_t phy_copy; 1888 1889 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1890 PHYMOD_IF_ERR_RETURN 1891 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1892 phy_copy.access.lane_mask = 1 << lane_id; 1893 1894 PHYMOD_IF_ERR_RETURN 1895 (merlin16_tsc_rx_ppm(&phy_copy.access, rx_ppm)); 1896 1897 return PHYMOD_E_NONE; 1898 } 1899 1900 int qtce16_phy_synce_clk_ctrl_set(const phymod_phy_access_t* phy, 1901 phymod_synce_clk_ctrl_t cfg) 1902 { 1903 int lane_id, sub_port; 1904 phymod_phy_access_t phy_copy; 1905 1906 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1907 PHYMOD_IF_ERR_RETURN 1908 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1909 phy_copy.access.lane_mask = 1 << lane_id; 1910 1911 PHYMOD_IF_ERR_RETURN 1912 (qmod16_synce_mode_set(&phy_copy.access, cfg.stg0_mode, cfg.stg1_mode)); 1913 1914 PHYMOD_IF_ERR_RETURN 1915 (qmod16_synce_clk_ctrl_set(&phy_copy.access, cfg.sdm_val)); 1916 1917 return PHYMOD_E_NONE; 1918 } 1919 1920 int qtce16_phy_synce_clk_ctrl_get(const phymod_phy_access_t* phy, 1921 phymod_synce_clk_ctrl_t *cfg) 1922 { 1923 int lane_id, sub_port; 1924 phymod_phy_access_t phy_copy; 1925 1926 PHYMOD_MEMCPY(&phy_copy, phy, sizeof(phy_copy)); 1927 PHYMOD_IF_ERR_RETURN 1928 (qmod16_lane_info(&phy->access, &lane_id, &sub_port)); 1929 phy_copy.access.lane_mask = 1 << lane_id; 1930 1931 PHYMOD_IF_ERR_RETURN 1932 (qmod16_synce_mode_get(&phy_copy.access, &(cfg->stg0_mode), &(cfg->stg1_mode))); 1933 1934 PHYMOD_IF_ERR_RETURN 1935 (qmod16_synce_clk_ctrl_get(&phy_copy.access, &(cfg->sdm_val))); 1936 1937 return PHYMOD_E_NONE; 1938 } 1939 1940 #endif /* PHYMOD_QTCE16_SUPPORT */