miim.c (106213B)
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 * MII Management (MDIO) bus access routines for reading and writing PHY 8 * registers. 9 * 10 * BCM5690 has an internal MDIO bus in addition to the external one. 11 * The internal bus is accessed by setting bit 7 in the PHY ID. 12 */ 13 14 #include <shared/bsl.h> 15 16 #include <sal/core/libc.h> 17 #include <sal/core/boot.h> 18 19 #include <soc/mem.h> 20 #include <soc/debug.h> 21 #include <soc/cm.h> 22 #include <soc/drv.h> 23 #include <soc/error.h> 24 #include <soc/cmic.h> 25 #include <soc/phyreg.h> 26 #include <soc/linkctrl.h> 27 #ifdef BCM_CMICM_SUPPORT 28 #include <soc/cmicm.h> 29 #endif 30 31 #ifdef PORTMOD_SUPPORT 32 #include <soc/portmod/portmod.h> 33 #endif /* PORTMOD_SUPPORT*/ 34 35 #ifdef BCM_CMICX_SUPPORT 36 #include <soc/cmicx_miim.h> 37 #endif 38 39 #define MIIM_POLL_TIMEOUT 250 40 41 #if defined(BCM_SAND_SUPPORT) 42 43 int 44 soc_dcmn_miim_operation(int unit, int is_write, int clause, uint32 phy_id, 45 uint32 phy_reg_addr, uint16 *phy_data) 46 { 47 int rv = SOC_E_NONE; 48 int clause45; 49 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 50 uint32 reg_val, real_phy_id, real_bus_id, internal_select, lsrv; 51 52 clause45 = (45 == clause); 53 54 /* Pause link scanning */ 55 rv = soc_linkctrl_linkscan_pause(unit); 56 if (rv != SOC_E_NONE) { 57 LOG_ERROR(BSL_LS_SOC_COMMON, 58 (BSL_META_U(unit, 59 "soc_linkctrl_linkscan_pause failed\n"))); 60 return rv; 61 } 62 63 /* hold MIIM lock */ 64 MIIM_LOCK(unit); 65 66 /* write reg_addr and c45 extention address or if c22: just reg addr */ 67 reg_val = 0; 68 if (clause45){ 69 soc_reg_field_set(unit, CMIC_MIIM_ADDRESSr, ®_val, CLAUSE_45_REGADRf, SOC_PHY_CLAUSE45_REGAD(phy_reg_addr)); 70 soc_reg_field_set(unit, CMIC_MIIM_ADDRESSr, ®_val, CLAUSE_45_DTYPEf, SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr)); 71 } else { 72 soc_reg_field_set(unit, CMIC_MIIM_ADDRESSr, ®_val, CLAUSE_22_REGADRf, phy_reg_addr); 73 } 74 WRITE_CMIC_MIIM_ADDRESSr(unit, reg_val); 75 76 /* write the parameters */ 77 reg_val = 0; 78 internal_select = (phy_id & 0x80) ? 1 : 0; 79 real_phy_id = phy_id & ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 80 real_phy_id &= ~(0x80); /*clear internal / external bit*/ 81 real_bus_id = PHY_ID_BUS_NUM(phy_id); 82 83 if (clause45){ 84 LOG_DEBUG(BSL_LS_SOC_MIIM, 85 (BSL_META_U(unit, 86 "soc_dcmn_miim_operation cl45 %s: " 87 "(id=0x%02x readr=0x%x dtype=0x%x data=0x%04x clause45=%d, real_phy_id=%d, real_bus_id=%d)\n"), 88 is_write ? "write" : "read ", phy_id, SOC_PHY_CLAUSE45_REGAD(phy_reg_addr), SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr), *phy_data, clause45, 89 real_phy_id,real_bus_id)); 90 } else { 91 LOG_DEBUG(BSL_LS_SOC_MIIM, 92 (BSL_META_U(unit, 93 "soc_dcmn_miim_operation cl22 %s: " 94 "(id=0x%02x addr=0x%02x data=0x%04x clause45=%d, real_phy_id=%d, real_bus_id=%d)\n"), 95 is_write ? "write" : "read ", phy_id, phy_reg_addr, *phy_data, clause45,real_phy_id,real_bus_id)); 96 } 97 98 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, ®_val, INTERNAL_SELf, internal_select); 99 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, ®_val, C45_SELf, clause45); 100 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, ®_val, PHY_IDf, real_phy_id); 101 if(is_write) { 102 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, ®_val, PHY_DATAf, *phy_data); 103 } else { 104 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, ®_val, PHY_DATAf, 0x0); 105 } 106 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, ®_val, BUS_IDf, real_bus_id); 107 WRITE_CMIC_MIIM_PARAMr(unit, reg_val); 108 109 /* start the access */ 110 READ_CMIC_SCHAN_CTRLr(unit, ®_val); 111 if(is_write) { 112 /*MIIM_WR_STARTf*/ 113 WRITE_CMIC_SCHAN_CTRLr(unit, 0x91); 114 } else { 115 /*MIIM_RD_STARTf*/ 116 WRITE_CMIC_SCHAN_CTRLr(unit, 0x90); 117 } 118 119 120 /* Wait for completion using either the interrupt or polling method */ 121 122 if (SOC_CONTROL(unit)->miimIntrEnb) { 123 soc_intr_enable(unit, IRQ_MIIM_OP_DONE); 124 125 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 126 SOC_CONTROL(unit)->miimTimeout) != 0) { 127 if ((soc_pci_read(unit, SOC_REG_INFO(unit,CMIC_SCHAN_CTRLr).offset) & 128 SC_MIIM_OP_DONE_TST) == 0) { 129 /* MIIM HW operation not complete */ 130 rv = SOC_E_TIMEOUT; 131 } else { 132 /* MIIM HW operation complete but no intr received yet 133 * Retry for MIIM Intr for busy system 134 * before declaring timeout */ 135 rv = SOC_E_TIMEOUT; 136 while (miim_intr_retry_cnt) { 137 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 138 MIIM_INTR_RETRY_TIMEOUT) == 0) { 139 rv = SOC_E_NONE; 140 break; 141 } 142 miim_intr_retry_cnt--; 143 } 144 } 145 } else { 146 LOG_DEBUG(BSL_LS_SOC_MIIM, 147 (BSL_META_U(unit, 148 " Interrupt received\n"))); 149 } 150 151 soc_intr_disable(unit, IRQ_MIIM_OP_DONE); 152 153 } else { 154 soc_timeout_t to; 155 156 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, 2500); 157 158 while ((soc_pci_read(unit, SOC_REG_INFO(unit,CMIC_SCHAN_CTRLr).offset) & 159 SC_MIIM_OP_DONE_TST) == 0) { 160 if (soc_timeout_check(&to)) { 161 rv = SOC_E_TIMEOUT; 162 break; 163 } 164 } 165 166 if (rv == SOC_E_NONE) { 167 LOG_DEBUG(BSL_LS_SOC_MIIM, 168 (BSL_META_U(unit, 169 " Done in %d polls\n"), to.polls)); 170 } 171 172 WRITE_CMIC_SCHAN_CTRLr(unit, SC_MIIM_OP_DONE_CLR); 173 174 } 175 176 if (rv == SOC_E_TIMEOUT) { 177 if(is_write) { 178 LOG_ERROR(BSL_LS_SOC_COMMON, 179 (BSL_META_U(unit, 180 "MiimTimeOut:soc_dcmn_miim_operation write, " 181 "timeout (id=0x%02x addr=0x%02x data=0x%04x)\n"), 182 phy_id, phy_reg_addr, *phy_data)); 183 } else /*read*/{ 184 LOG_ERROR(BSL_LS_SOC_COMMON, 185 (BSL_META_U(unit, 186 "MiimTimeOut:soc_dcmn_miim_operation read, " 187 "timeout (id=0x%02x addr=0x%02x)\n"), 188 phy_id, phy_reg_addr)); 189 } 190 SOC_CONTROL(unit)->stat.err_mii_tmo++; 191 } 192 193 /* read data */ 194 if(SOC_E_NONE == rv && !is_write) { 195 *phy_data = (uint16)soc_pci_read(unit, SOC_REG_INFO(unit,CMIC_MIIM_READ_DATAr).offset); 196 LOG_VERBOSE(BSL_LS_SOC_MIIM, 197 (BSL_META_U(unit, 198 "soc_dcmn_miim_operation read data: %d \n"),*phy_data)); 199 } 200 201 /* Release linkscan pause and MIIM lock */ 202 MIIM_UNLOCK(unit); 203 204 lsrv = soc_linkctrl_linkscan_continue(unit); 205 if(SOC_E_NONE != lsrv) { 206 LOG_ERROR(BSL_LS_SOC_COMMON, 207 (BSL_META_U(unit, 208 "soc_linkctrl_linkscan_continue failed\n"))); 209 rv = lsrv; 210 } 211 212 return rv; 213 } 214 215 #if defined(BCM_CMICM_SUPPORT) 216 217 #define SOC_DCMN_MIIM_FORCE_CL45_BIT (21) 218 219 int 220 soc_dcmn_cmicm_miim_operation(int unit, int is_write, int clause, uint32 phy_id, 221 uint32 phy_reg_addr, uint16 *phy_data) 222 { 223 int rv = SOC_E_NONE; 224 int clause45, cmc; 225 uint32 reg_val, real_phy_id, real_bus_id, internal_select, lsrv; 226 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 227 228 cmc = SOC_PCI_CMC(unit); 229 230 clause45 = (45 == clause); 231 232 233 SHR_BITCLR(&phy_reg_addr, SOC_DCMN_MIIM_FORCE_CL45_BIT); 234 235 /* Pause link scanning */ 236 rv = soc_linkctrl_linkscan_pause(unit); 237 if (rv != SOC_E_NONE) { 238 LOG_ERROR(BSL_LS_SOC_COMMON, 239 (BSL_META_U(unit, 240 "soc_linkctrl_linkscan_pause failed\n"))); 241 return rv; 242 } 243 244 MIIM_LOCK(unit); 245 246 /* write reg_addr and c45 extention address or if c22: just reg addr */ 247 reg_val = 0; 248 if (clause45){ 249 soc_reg_field_set(unit, CMIC_CMC0_MIIM_ADDRESSr, ®_val, CLAUSE_45_REGADRf, SOC_PHY_CLAUSE45_REGAD(phy_reg_addr)); 250 soc_reg_field_set(unit, CMIC_CMC0_MIIM_ADDRESSr, ®_val, CLAUSE_45_DTYPEf, SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr)); 251 } else { 252 /* CLAUSE_22_REGADRf does not exist in CMICD register spec*/ 253 reg_val = phy_reg_addr & 0x1f; 254 } 255 soc_pci_write(unit, CMIC_CMCx_MIIM_ADDRESS_OFFSET(cmc), reg_val); 256 257 /* write the parameters */ 258 reg_val = 0; 259 internal_select = (phy_id & 0x80) ? 1 : 0; 260 real_phy_id = phy_id & ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 261 real_phy_id &= ~(0x80); /*clear internal / external bit*/ 262 real_bus_id = PHY_ID_BUS_NUM(phy_id); 263 264 if (clause45){ 265 LOG_DEBUG(BSL_LS_SOC_MIIM, 266 (BSL_META_U(unit, 267 "soc_dcmn_cmicm_miim_operation cl45 %s: " 268 "(id=0x%02x readr=0x%x dtype=0x%x data=0x%04x clause45=%d, real_phy_id=%d, real_bus_id=%d)\n"), 269 is_write ? "write" : "read ", phy_id, SOC_PHY_CLAUSE45_REGAD(phy_reg_addr), SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr), *phy_data, clause45, 270 real_phy_id,real_bus_id)); 271 } else { 272 LOG_DEBUG(BSL_LS_SOC_MIIM, 273 (BSL_META_U(unit, 274 "soc_dcmn_cmicm_miim_operation cl22 %s: " 275 "(id=0x%02x addr=0x%02x data=0x%04x clause45=%d, real_phy_id=%d, real_bus_id=%d)\n"), 276 is_write ? "write" : "read ", phy_id, phy_reg_addr, *phy_data, clause45,real_phy_id,real_bus_id)); 277 } 278 279 280 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, ®_val, INTERNAL_SELf, internal_select); 281 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, ®_val, C45_SELf, clause45); 282 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, ®_val, PHY_IDf, real_phy_id); 283 if(is_write) { 284 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, ®_val, PHY_DATAf, *phy_data); 285 } else { 286 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, ®_val, PHY_DATAf, 0x0); 287 } 288 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, ®_val, BUS_IDf, real_bus_id); 289 soc_pci_write(unit, CMIC_CMCx_MIIM_PARAM_OFFSET(cmc), reg_val); 290 291 /* start the access */ 292 if(is_write) { 293 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 1); 294 } else { 295 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 2); 296 } 297 298 299 /* Wait for completion using either the interrupt or polling method */ 300 301 if (SOC_CONTROL(unit)->miimIntrEnb) { 302 303 soc_cmicm_intr0_enable(unit, IRQ_CMCx_MIIM_OP_DONE); 304 305 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 306 SOC_CONTROL(unit)->miimTimeout) != 0) { 307 if ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 308 CMIC_MIIM_OPN_DONE) == 0) { 309 /* MIIM HW operation not complete */ 310 rv = SOC_E_TIMEOUT; 311 } else { 312 /* MIIM HW operation complete but no intr received yet 313 * Retry for MIIM Intr for busy system 314 * before declaring timeout */ 315 rv = SOC_E_TIMEOUT; 316 while (miim_intr_retry_cnt) { 317 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 318 MIIM_INTR_RETRY_TIMEOUT) == 0) { 319 rv = SOC_E_NONE; 320 break; 321 } 322 miim_intr_retry_cnt--; 323 } 324 } 325 } else { 326 LOG_DEBUG(BSL_LS_SOC_MIIM, 327 (BSL_META_U(unit, 328 " Interrupt received\n"))); 329 } 330 331 soc_cmicm_intr0_disable(unit, IRQ_CMCx_MIIM_OP_DONE); 332 333 } else { 334 soc_timeout_t to; 335 336 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, 2500); 337 338 while ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 339 CMIC_MIIM_OPN_DONE) == 0) { 340 if (soc_timeout_check(&to)) { 341 rv = SOC_E_TIMEOUT; 342 break; 343 } 344 } 345 346 if (rv == SOC_E_NONE) { 347 LOG_DEBUG(BSL_LS_SOC_MIIM, 348 (BSL_META_U(unit, 349 " Done in %d polls\n"), to.polls)); 350 } 351 352 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 0); 353 354 } 355 356 if (rv == SOC_E_TIMEOUT) { 357 if(is_write) { 358 LOG_ERROR(BSL_LS_SOC_COMMON, 359 (BSL_META_U(unit, 360 "MiimTimeOut:soc_dcmn_miim_operation write, " 361 "timeout (id=0x%02x addr=0x%02x data=0x%04x)\n"), 362 phy_id, phy_reg_addr, *phy_data)); 363 } else /*read*/{ 364 LOG_ERROR(BSL_LS_SOC_COMMON, 365 (BSL_META_U(unit, 366 "MiimTimeOut:soc_dcmn_miim_operation read, " 367 "timeout (id=0x%02x addr=0x%02x)\n"), 368 phy_id, phy_reg_addr)); 369 } 370 SOC_CONTROL(unit)->stat.err_mii_tmo++; 371 } 372 373 /* read data */ 374 if(SOC_E_NONE == rv && !is_write) { 375 *phy_data = (uint16)soc_pci_read(unit, CMIC_CMCx_MIIM_READ_DATA_OFFSET(cmc)); 376 LOG_VERBOSE(BSL_LS_SOC_MIIM, 377 (BSL_META_U(unit, 378 "soc_dcmn_miim_operation read data: %d \n"),*phy_data)); 379 380 } 381 382 /* Release linkscan pause and MIIM lock */ 383 MIIM_UNLOCK(unit); 384 385 lsrv = soc_linkctrl_linkscan_continue(unit); 386 if(SOC_E_NONE != lsrv) { 387 LOG_ERROR(BSL_LS_SOC_COMMON, 388 (BSL_META_U(unit, 389 "soc_linkctrl_linkscan_continue failed\n"))); 390 rv = lsrv; 391 } 392 393 394 return rv; 395 } 396 397 #endif /*BCM_CMICM_SUPPORT*/ 398 399 /* 400 * Function: 401 * soc_dcmn_miim_write 402 * Purpose: 403 * Interface to write a value to a MIIM register. 404 * Parameters: 405 * unit - StrataSwitch Unit #. 406 * phy_id - Phy ID to write (MIIM address) 407 * phy_reg_addr - PHY register to write 408 * phy_wr_data - Data to write. 409 * Returns: 410 * SOC_E_XXX 411 */ 412 413 /*user defined function for external phy*/ 414 #ifdef USER_DEFINED_EXT_MDIO_FUNCTION 415 extern int _user_defined_ext_mdio_write(int unit, int clause, uint32 phy_id, 416 uint32 phy_reg_addr, uint16 phy_wr_data); 417 #endif 418 419 int 420 soc_dcmn_miim_write(int unit, int clause, uint32 phy_id, 421 uint32 phy_reg_addr, uint16 phy_wr_data) 422 { 423 #ifdef USER_DEFINED_EXT_MDIO_FUNCTION 424 uint32 internal_select; 425 #endif 426 427 #ifdef USER_DEFINED_EXT_MDIO_FUNCTION 428 internal_select = (phy_id & 0x80) ? 1 : 0; 429 if (!internal_select) { 430 return _user_defined_ext_mdio_write(unit, clause, phy_id, phy_reg_addr, phy_wr_data); 431 } 432 #endif 433 434 #ifdef BCM_CMICX_SUPPORT 435 if (soc_feature(unit, soc_feature_cmicx)) { 436 return soc_cmicx_miim_operation(unit, TRUE, clause, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, phy_id, 437 phy_reg_addr, &phy_wr_data); 438 } else 439 #endif /* BCM_CMICX_SUPPORT */ 440 #if defined(BCM_CMICM_SUPPORT) 441 if(soc_feature(unit, soc_feature_cmicm)) { 442 return soc_dcmn_cmicm_miim_operation(unit, TRUE, clause, phy_id, 443 phy_reg_addr, &phy_wr_data); 444 } else 445 #endif 446 { 447 return soc_dcmn_miim_operation(unit, TRUE, clause, phy_id, 448 phy_reg_addr, &phy_wr_data); 449 } 450 } 451 452 453 int 454 soc_dcmn_miim_cl22_write(int unit, uint32 phy_id, 455 uint32 phy_reg_addr, uint16 phy_wr_data) 456 { 457 return soc_dcmn_miim_write(unit, 22, phy_id, phy_reg_addr, phy_wr_data); 458 } 459 460 int 461 soc_dcmn_miim_cl45_write(int unit, uint32 phy_id, 462 uint32 phy_reg_addr, uint16 phy_wr_data) 463 { 464 return soc_dcmn_miim_write(unit, 45, phy_id, phy_reg_addr, phy_wr_data); 465 } 466 467 468 469 /* 470 * Function: 471 * soc_dcmn_miim_read 472 * Purpose: 473 * Interface to read a value from a MIIM register. 474 * Parameters: 475 * unit - StrataSwitch Unit #. 476 * phy_id - Phy ID to write (MIIM address) 477 * phy_reg_addr - PHY register to write 478 * phy_rd_data - Data read. 479 * Returns: 480 * SOC_E_XXX 481 */ 482 /*user defined function for external phy*/ 483 #ifdef USER_DEFINED_EXT_MDIO_FUNCTION 484 extern int _user_defined_ext_mdio_read(int unit, int clause, uint32 phy_id, 485 uint32 phy_reg_addr, uint16 *phy_rd_data); 486 #endif 487 488 int 489 soc_dcmn_miim_read(int unit, int clause, uint32 phy_id, 490 uint32 phy_reg_addr, uint16 *phy_rd_data) 491 { 492 #ifdef USER_DEFINED_EXT_MDIO_FUNCTION 493 uint32 internal_select; 494 #endif 495 496 497 #ifdef USER_DEFINED_EXT_MDIO_FUNCTION 498 internal_select = (phy_id & 0x80) ? 1 : 0; 499 if (!internal_select) { 500 return _user_defined_ext_mdio_read(unit, clause, phy_id, phy_reg_addr, phy_rd_data); 501 } 502 #endif 503 504 #ifdef BCM_CMICX_SUPPORT 505 if (soc_feature(unit, soc_feature_cmicx)) { 506 return soc_cmicx_miim_operation(unit, FALSE, clause, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, phy_id, 507 phy_reg_addr, phy_rd_data); 508 } else 509 #endif /* BCM_CMICX_SUPPORT */ 510 #if defined(BCM_CMICM_SUPPORT) 511 if(soc_feature(unit, soc_feature_cmicm)) { 512 return soc_dcmn_cmicm_miim_operation(unit, FALSE, clause, phy_id, 513 phy_reg_addr, phy_rd_data); 514 } else 515 #endif 516 { 517 return soc_dcmn_miim_operation(unit, FALSE, clause, phy_id, 518 phy_reg_addr, phy_rd_data); 519 } 520 } 521 522 523 int 524 soc_dcmn_miim_cl22_read(int unit, uint32 phy_id, 525 uint32 phy_reg_addr, uint16 *phy_rd_data) 526 { 527 return soc_dcmn_miim_read(unit, 22, phy_id, phy_reg_addr, phy_rd_data); 528 } 529 530 int 531 soc_dcmn_miim_cl45_read(int unit, uint32 phy_id, 532 uint32 phy_reg_addr, uint16 *phy_rd_data) 533 { 534 return soc_dcmn_miim_read(unit, 45, phy_id, phy_reg_addr, phy_rd_data); 535 } 536 537 #endif /*BCM_SAND_SUPPORT */ 538 539 540 541 #if defined(BCM_RCPU_SUPPORT) && defined(BCM_CMICM_SUPPORT) 542 /* 543 */ 544 545 /* 546 * Function: 547 * soc_rcpu_miim_write 548 * Purpose: 549 * Write a value to a MIIM register throuth RCPU packets. 550 * Parameters: 551 * unit - StrataSwitch Unit #. 552 * phy_id - Phy ID to write (MIIM address) 553 * phy_reg_addr - PHY register to write 554 * phy_wr_data - Data to write. 555 * Returns: 556 * SOC_E_XXX 557 * Notes: 558 * Temporarily disables auto link scan if it was enabled. The MIIM 559 * registers are locked during the operation to prevent multiple 560 * tasks from trying to access PHY registers simultaneously. 561 * If remote interrupt packet is enabled for RCPU MIIM access, the register 562 * CMIC_INTR_PKT_PACING_DELAY should be programmed properly to allow 563 * continuous generation of interrupt packets. 564 */ 565 int 566 soc_rcpu_miim_write(int unit, uint16 phy_id, 567 uint8 phy_reg_addr, uint16 phy_wr_data) 568 { 569 int rv = SOC_E_NONE; 570 int clause45; 571 uint32 phy_param; 572 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 573 574 assert(!sal_int_context()); 575 576 LOG_VERBOSE(BSL_LS_SOC_MIIM, 577 (BSL_META_U(unit, 578 "soc_rcpu_miim_write: id=0x%02x addr=0x%02x data=0x%04x\n"), 579 phy_id, phy_reg_addr, phy_wr_data)); 580 581 if(!soc_feature(unit, soc_feature_cmicm)) { 582 return SOC_E_UNAVAIL; 583 } 584 585 clause45 = soc_feature(unit, soc_feature_phy_cl45); 586 587 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_CMICM_SUPPORT) 588 /* 589 * Trident Switch And Later 590 * internal select bit 25 591 * BUS_ID bit 22-24 592 * C45_SEL bit 21 593 */ 594 if (SOC_IS_TD_TT(unit) || soc_feature(unit, soc_feature_cmicm)) { 595 596 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 597 598 /* set 5-bit PHY MDIO address */ 599 phy_param = (uint32)phy_wr_data | 600 (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 601 602 /* select internal MDIO bus if set */ 603 if (phy_id & 0x80) { /* Internal/External select */ 604 #if defined(BCM_CMICDV3_SUPPORT) 605 /* 606 * Apache and Tomahawk2 Switches And Later 607 * internal select bit 26 608 * BUS_ID bit 22-25 609 * C45_SEL bit 21 610 * See CMIC_CMC0_MIIM_PARAM register. 611 */ 612 if (soc_feature(unit, soc_feature_cmicd_v3)) { 613 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 10)); 614 } else 615 #endif /* BCM_CMICDV3_SUPPORT */ 616 { 617 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 9)); 618 } 619 } 620 621 /* set MDIO bus number */ 622 phy_param |= (bus_sel << (MIIM_PARAM_ID_OFFSET + 6)); 623 } else 624 #endif 625 626 #ifdef BCM_TRX_SUPPORT 627 628 if (SOC_IS_TRX(unit)) { 629 int bus_sel = (phy_id & 0x60) >> 5; 630 631 phy_param = (uint32)phy_wr_data | 632 (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 633 634 if (phy_id & 0x80) { /* Internal/External select */ 635 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 7)); 636 } 637 if (bus_sel == 1) { 638 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 6)); 639 } else if (bus_sel == 2) { 640 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 8)); 641 } 642 } else 643 #endif /* BCM_TRX_SUPPORT */ 644 { 645 phy_param = ((uint32)phy_id << MIIM_PARAM_ID_OFFSET | 646 (uint32)phy_wr_data); 647 } 648 649 /* Pause link scanning - and hold MIIM lock */ 650 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 651 soc_linkscan_pause(unit); 652 } 653 MIIM_LOCK(unit); 654 655 /* Write parameter register and tell CMIC to start */ 656 657 /* Clause 45 support changes Clause 22 access method */ 658 if (clause45) { 659 soc_pci_write(unit, CMIC_RPE_MIIM_ADDRESS_OFFSET, phy_reg_addr); 660 } else { 661 phy_param |= (uint32)phy_reg_addr << MIIM_PARAM_REG_ADDR_OFFSET; 662 } 663 664 soc_pci_write(unit, CMIC_RPE_MIIM_PARAM_OFFSET, phy_param); 665 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 1); 666 667 /* Wait for completion using either the interrupt or polling method */ 668 if (SOC_CONTROL(unit)->miimIntrEnb) { 669 soc_cmicm_rcpu_intr0_enable(unit, IRQ_RCPU_MIIM_OP_DONE); 670 671 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 672 SOC_CONTROL(unit)->miimTimeout) != 0) { 673 if ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 674 CMIC_MIIM_OPN_DONE) == 0) { 675 /* MIIM HW operation not complete */ 676 rv = SOC_E_TIMEOUT; 677 } else { 678 /* MIIM HW operation complete but no intr received yet 679 * Retry for MIIM Intr for busy system 680 * before declaring timeout */ 681 rv = SOC_E_TIMEOUT; 682 while (miim_intr_retry_cnt) { 683 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 684 MIIM_INTR_RETRY_TIMEOUT) == 0) { 685 rv = SOC_E_NONE; 686 break; 687 } 688 miim_intr_retry_cnt--; 689 } 690 } 691 } else { 692 LOG_DEBUG(BSL_LS_SOC_MIIM, 693 (BSL_META_U(unit, 694 " Interrupt received\n"))); 695 } 696 697 soc_cmicm_rcpu_intr0_disable(unit, IRQ_RCPU_MIIM_OP_DONE); 698 } else { 699 soc_timeout_t to; 700 701 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, 250); 702 703 while ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 704 CMIC_MIIM_OPN_DONE) == 0) { 705 if (soc_timeout_check(&to)) { 706 rv = SOC_E_TIMEOUT; 707 break; 708 } 709 } 710 711 if (rv == SOC_E_NONE) { 712 LOG_DEBUG(BSL_LS_SOC_MIIM, 713 (BSL_META_U(unit, 714 " Done in %d polls\n"), to.polls)); 715 } 716 717 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 0); 718 } 719 if (rv == SOC_E_TIMEOUT) { 720 LOG_ERROR(BSL_LS_SOC_COMMON, 721 (BSL_META_U(unit, 722 "MiimTimeOut:soc_rcpu_miim_write, " 723 "timeout (id=0x%02x addr=0x%02x data=0x%04x)\n"), 724 phy_id, phy_reg_addr, phy_wr_data)); 725 SOC_CONTROL(unit)->stat.err_mii_tmo++; 726 } 727 728 /* Release linkscan pause and MIIM lock */ 729 730 MIIM_UNLOCK(unit); 731 732 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 733 soc_linkscan_continue(unit); 734 } 735 736 return rv; 737 738 } 739 /* 740 * Function: 741 * soc_rcpu_miim_read 742 * Purpose: 743 * Read a value from an MII register. 744 * Parameters: 745 * unit - StrataSwitch Unit #. 746 * phy_id - Phy ID to write (MIIM address) 747 * phy_reg_addr - PHY register to write 748 * phy_rd_data - 16bit data to write into 749 * Returns: 750 * SOC_E_XXX 751 * Notes: 752 * Temporarily disables auto link scan if it was enabled. The MIIM 753 * registers are locked during the operation to prevent multiple 754 * tasks from trying to access PHY registers simultaneously. 755 * If remote interrupt packet is enabled for RCPU MIIM access, the register 756 * CMIC_INTR_PKT_PACING_DELAY should be programmed properly to allow 757 * continuous generation of interrupt packets. 758 */ 759 760 int 761 soc_rcpu_miim_read(int unit, uint16 phy_id, 762 uint8 phy_reg_addr, uint16 *phy_rd_data) 763 { 764 int rv = SOC_E_NONE; 765 int clause45; 766 uint32 phy_param; 767 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 768 769 assert(!sal_int_context()); 770 assert(phy_rd_data); 771 772 LOG_VERBOSE(BSL_LS_SOC_MIIM, 773 (BSL_META_U(unit, 774 "soc_rcpu_miim_read: id=0x%02x addr=0x%02x "), 775 phy_id, phy_reg_addr)); 776 777 if(!soc_feature(unit, soc_feature_cmicm)) { 778 return SOC_E_UNAVAIL; 779 } 780 781 782 clause45 = soc_feature(unit, soc_feature_phy_cl45); 783 784 /* 785 * Trident Switch And Katana 786 * internal select bit 25 787 * BUS_ID bit 22-24 788 * C45_SEL bit 21 789 */ 790 if (SOC_IS_TD_TT(unit) || SOC_IS_KATANA(unit) || SOC_IS_TRIUMPH3(unit)) { 791 792 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 793 794 /* set 5-bit PHY MDIO address */ 795 phy_param = (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 796 797 /* select internal MDIO bus if set */ 798 if (phy_id & 0x80) { /* Internal/External select */ 799 #if defined(BCM_CMICDV3_SUPPORT) 800 /* 801 * Apache and Tomahawk2 Switches And Later 802 * internal select bit 26 803 * BUS_ID bit 22-25 804 * C45_SEL bit 21 805 * See CMIC_CMC0_MIIM_PARAM register. 806 */ 807 if (soc_feature(unit, soc_feature_cmicd_v3)) { 808 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 10)); 809 } else 810 #endif /* BCM_CMICDV3_SUPPORT */ 811 { 812 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 9)); 813 } 814 } 815 816 /* set MDIO bus number */ 817 phy_param |= (bus_sel << (MIIM_PARAM_ID_OFFSET + 6)); 818 } else 819 #ifdef BCM_TRX_SUPPORT 820 821 if (SOC_IS_TRX(unit)) { 822 int bus_sel = (phy_id & 0x60) >> 5; 823 824 phy_param = (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 825 826 if (phy_id & 0x80) { /* Internal/External select */ 827 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 7)); 828 } 829 if (bus_sel == 1) { 830 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 6)); 831 } else if (bus_sel == 2) { 832 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 8)); 833 } 834 } else 835 #endif /* BCM_TRX_SUPPORT */ 836 { 837 phy_param = (uint32)phy_id << MIIM_PARAM_ID_OFFSET; 838 } 839 840 /* Pause link scanning - and hold MIIM lock */ 841 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 842 soc_linkscan_pause(unit); 843 } 844 MIIM_LOCK(unit); 845 846 /* Write parameter register and tell CMIC to start */ 847 848 /* Clause 45 support changes Clause 22 access method */ 849 if (clause45) { 850 soc_pci_write(unit, CMIC_RPE_MIIM_ADDRESS_OFFSET, phy_reg_addr); 851 } else { 852 phy_param |= (uint32)phy_reg_addr << MIIM_PARAM_REG_ADDR_OFFSET; 853 } 854 855 soc_pci_write(unit, CMIC_RPE_MIIM_PARAM_OFFSET, phy_param); 856 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 2); 857 858 /* Wait for completion using either the interrupt or polling method */ 859 if (SOC_CONTROL(unit)->miimIntrEnb) { 860 soc_cmicm_rcpu_intr0_enable(unit, IRQ_RCPU_MIIM_OP_DONE); 861 862 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 863 SOC_CONTROL(unit)->miimTimeout) != 0) { 864 if ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 865 CMIC_MIIM_OPN_DONE) == 0) { 866 /* MIIM HW operation not complete */ 867 rv = SOC_E_TIMEOUT; 868 } else { 869 /* MIIM HW operation complete but no intr received yet 870 * Retry for MIIM Intr for busy system 871 * before declaring timeout */ 872 rv = SOC_E_TIMEOUT; 873 while (miim_intr_retry_cnt) { 874 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 875 MIIM_INTR_RETRY_TIMEOUT) == 0) { 876 rv = SOC_E_NONE; 877 break; 878 } 879 miim_intr_retry_cnt--; 880 } 881 } 882 } else { 883 LOG_DEBUG(BSL_LS_SOC_MIIM, 884 (BSL_META_U(unit, 885 " Interrupt received\n"))); 886 } 887 888 soc_cmicm_rcpu_intr0_disable(unit, IRQ_RCPU_MIIM_OP_DONE); 889 } else { 890 soc_timeout_t to; 891 892 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, 250); 893 894 while ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 895 CMIC_MIIM_OPN_DONE) == 0) { 896 if (soc_timeout_check(&to)) { 897 rv = SOC_E_TIMEOUT; 898 break; 899 } 900 } 901 902 if (rv == SOC_E_NONE) { 903 LOG_DEBUG(BSL_LS_SOC_MIIM, 904 (BSL_META_U(unit, 905 " Done in %d polls\n"), to.polls)); 906 } 907 908 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 0); 909 } 910 911 if (rv == SOC_E_TIMEOUT) { 912 LOG_ERROR(BSL_LS_SOC_COMMON, 913 (BSL_META_U(unit, 914 "MiimTimeOut:soc_rcpu_miim_read, " 915 "timeout (id=0x%02x addr=0x%02x)\n"), 916 phy_id, phy_reg_addr)); 917 SOC_CONTROL(unit)->stat.err_mii_tmo++; 918 } else { 919 *phy_rd_data = (uint16)soc_pci_read(unit, CMIC_RPE_MIIM_READ_DATA_OFFSET); 920 921 LOG_VERBOSE(BSL_LS_SOC_MIIM, 922 (BSL_META_U(unit, 923 "data=0x%04x\n"), *phy_rd_data)); 924 } 925 926 /* Release linkscan pause and MIIM lock */ 927 928 MIIM_UNLOCK(unit); 929 930 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 931 soc_linkscan_continue(unit); 932 } 933 934 return rv; 935 936 } 937 /* 938 * Function: 939 * soc_rcpu_miimc45_write 940 * Purpose: 941 * Write a value to a MIIM register. 942 * Parameters: 943 * unit - StrataSwitch Unit #. 944 * phy_id - Phy ID to write (MIIM address) 945 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 946 * phy_reg_addr - PHY register to write 947 * phy_wr_data - Data to write. 948 * Returns: 949 * SOC_E_XXX 950 * Notes: 951 * Temporarily disables auto link scan if it was enabled. The MIIM 952 * registers are locked during the operation to prevent multiple 953 * tasks from trying to access PHY registers simultaneously. 954 * If remote interrupt packet is enabled for RCPU MIIM access, the register 955 * CMIC_INTR_PKT_PACING_DELAY should be programmed properly to allow 956 * continuous generation of interrupt packets. 957 */ 958 959 int 960 soc_rcpu_miimc45_write(int unit, uint16 phy_id, uint8 phy_devad, 961 uint16 phy_reg_addr, uint16 phy_wr_data) 962 { 963 int rv = SOC_E_NONE; 964 uint32 phy_param; 965 uint32 phy_miim_addr; 966 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 967 968 assert(!sal_int_context()); 969 970 if (SOC_WARM_BOOT(unit) || SOC_IS_RELOADING(unit)) { 971 return SOC_E_NONE; 972 } 973 974 LOG_VERBOSE(BSL_LS_SOC_MIIM, 975 (BSL_META_U(unit, 976 "soc_miimc45_write: id=0x%02x phy_devad=0x%02x " 977 "addr=0x%02x data=0x%04x\n"), 978 phy_id, phy_devad, phy_reg_addr, phy_wr_data)); 979 980 if (!soc_feature(unit, soc_feature_phy_cl45) || 981 !soc_feature(unit, soc_feature_cmicm)) { 982 return SOC_E_UNAVAIL; 983 } 984 985 /* Pause link scanning - and hold MIIM lock */ 986 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 987 soc_linkscan_pause(unit); 988 } 989 MIIM_LOCK(unit); 990 991 /* Write parameter registers and tell CMIC to start */ 992 phy_param = 0; 993 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 994 MIIM_CYCLEf, MIIM_CYCLE_AUTO); 995 if (phy_id & 0x80) { 996 phy_id &= (~0x80); 997 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, 998 &phy_param, INTERNAL_SELf, 1); 999 } 1000 1001 if (soc_feature(unit, soc_feature_mdio_enhanced)) { 1002 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, C45_SELf, 1); 1003 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_CMICM_SUPPORT) 1004 if (SOC_IS_TD_TT(unit) || soc_feature(unit, soc_feature_cmicm)) { 1005 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 1006 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1007 BUS_IDf, bus_sel); 1008 phy_id &= ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 1009 } else 1010 #endif 1011 #if defined(BCM_TRX_SUPPORT) 1012 if (SOC_IS_TRX(unit)) { 1013 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1014 BUS0_1_SELf, ((phy_id & 0x20) ? 1 : 0)); 1015 phy_id &= (~0x20); 1016 1017 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1018 BUS2_SELf, ((phy_id & 0x40) ? 1 : 0)); 1019 phy_id &= (~0x40); 1020 } else 1021 #endif /* BCM_TRX_SUPPORT */ 1022 { 1023 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, HG_SELf, 1024 ((phy_id & 0x40) ? 1 : 0)); 1025 phy_id &= (~0x40); 1026 } 1027 } 1028 1029 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, PHY_IDf, phy_id); 1030 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1031 PHY_DATAf, phy_wr_data); 1032 phy_miim_addr = 0; 1033 soc_reg_field_set(unit, CMIC_RPE_MIIM_ADDRESSr, &phy_miim_addr, 1034 CLAUSE_45_DTYPEf, phy_devad); 1035 soc_reg_field_set(unit, CMIC_RPE_MIIM_ADDRESSr, &phy_miim_addr, 1036 CLAUSE_45_REGADRf, phy_reg_addr); 1037 1038 soc_pci_write(unit, CMIC_RPE_MIIM_ADDRESS_OFFSET, phy_miim_addr); 1039 soc_pci_write(unit, CMIC_RPE_MIIM_PARAM_OFFSET, phy_param); 1040 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 1); 1041 1042 /* Wait for completion using either the interrupt or polling method */ 1043 if (SOC_CONTROL(unit)->miimIntrEnb) { 1044 soc_cmicm_rcpu_intr0_enable(unit, IRQ_RCPU_MIIM_OP_DONE); 1045 1046 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 1047 SOC_CONTROL(unit)->miimTimeout) != 0) { 1048 if ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 1049 CMIC_MIIM_OPN_DONE) == 0) { 1050 /* MIIM HW operation not complete */ 1051 rv = SOC_E_TIMEOUT; 1052 } else { 1053 /* MIIM HW operation complete but no intr received yet 1054 * Retry for MIIM Intr for busy system 1055 * before declaring timeout */ 1056 rv = SOC_E_TIMEOUT; 1057 while (miim_intr_retry_cnt) { 1058 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 1059 MIIM_INTR_RETRY_TIMEOUT) == 0) { 1060 rv = SOC_E_NONE; 1061 break; 1062 } 1063 miim_intr_retry_cnt--; 1064 } 1065 } 1066 } else { 1067 LOG_DEBUG(BSL_LS_SOC_MIIM, 1068 (BSL_META_U(unit, 1069 " Interrupt received\n"))); 1070 } 1071 1072 soc_cmicm_rcpu_intr0_disable(unit, IRQ_RCPU_MIIM_OP_DONE); 1073 } else { 1074 soc_timeout_t to; 1075 1076 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, 250); 1077 1078 while ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 1079 CMIC_MIIM_OPN_DONE) == 0) { 1080 if (soc_timeout_check(&to)) { 1081 rv = SOC_E_TIMEOUT; 1082 break; 1083 } 1084 } 1085 1086 if (rv == SOC_E_NONE) { 1087 LOG_DEBUG(BSL_LS_SOC_MIIM, 1088 (BSL_META_U(unit, 1089 " Done in %d polls\n"), to.polls)); 1090 } 1091 1092 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 0); 1093 } 1094 1095 if (rv == SOC_E_TIMEOUT) { 1096 LOG_ERROR(BSL_LS_SOC_COMMON, 1097 (BSL_META_U(unit, 1098 "MiimTimeOut:soc_miimc45_write, " 1099 "timeout (id=0x%02x addr=0x%02x data=0x%04x)\n"), 1100 phy_id, phy_reg_addr, phy_wr_data)); 1101 SOC_CONTROL(unit)->stat.err_mii_tmo++; 1102 } 1103 1104 /* Release linkscan pause and MIIM lock */ 1105 MIIM_UNLOCK(unit); 1106 1107 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 1108 soc_linkscan_continue(unit); 1109 } 1110 1111 return rv; 1112 1113 } 1114 /* 1115 * Function: 1116 * soc_rcpu_miimc45_read 1117 * Purpose: 1118 * Read a value from an MII register. 1119 * Parameters: 1120 * unit - StrataSwitch Unit #. 1121 * phy_id - Phy ID to write (MIIM address) 1122 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 1123 * phy_reg_addr - PHY register to write 1124 * phy_rd_data - 16bit data to write into 1125 * Returns: 1126 * SOC_E_XXX 1127 * Notes: 1128 * Temporarily disables auto link scan if it was enabled. The MIIM 1129 * registers are locked during the operation to prevent multiple 1130 * tasks from trying to access PHY registers simultaneously. 1131 * If remote interrupt packet is enabled for RCPU MIIM access, the register 1132 * CMIC_INTR_PKT_PACING_DELAY should be programmed properly to allow 1133 * continuous generation of interrupt packets. 1134 */ 1135 1136 int 1137 soc_rcpu_miimc45_read(int unit, uint16 phy_id, uint8 phy_devad, 1138 uint16 phy_reg_addr, uint16 *phy_rd_data) 1139 { 1140 int rv = SOC_E_NONE; 1141 uint32 phy_param, phy_miim_addr; 1142 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 1143 1144 assert(!sal_int_context()); 1145 assert(phy_rd_data); 1146 1147 LOG_VERBOSE(BSL_LS_SOC_MIIM, 1148 (BSL_META_U(unit, 1149 "soc_rcpu_miimc45_read: id=0x%02x " 1150 "phy_devad=0x%02x addr=0x%02x\n"), 1151 phy_id, phy_devad, phy_reg_addr)); 1152 1153 if (!soc_feature(unit, soc_feature_cmicm)|| 1154 !soc_feature(unit, soc_feature_phy_cl45)) { 1155 return SOC_E_UNAVAIL; 1156 } 1157 1158 /* Pause link scanning - and hold MIIM lock */ 1159 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 1160 soc_linkscan_pause(unit); 1161 } 1162 MIIM_LOCK(unit); 1163 1164 /* Write parameter registers and tell CMIC to start */ 1165 phy_param = 0; 1166 1167 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1168 MIIM_CYCLEf, MIIM_CYCLE_AUTO); 1169 1170 if (phy_id & 0x80) { 1171 phy_id &= (~0x80); 1172 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, 1173 &phy_param, INTERNAL_SELf, 1); 1174 1175 if (soc_feature(unit, soc_feature_mdio_enhanced)) { 1176 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, 1177 &phy_param, C45_SELf, 1); 1178 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_CMICM_SUPPORT) 1179 if (SOC_IS_TD_TT(unit) || soc_feature(unit, soc_feature_cmicm)) { 1180 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 1181 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1182 BUS_IDf, bus_sel); 1183 phy_id &= ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 1184 } else 1185 #endif 1186 #if defined(BCM_TRX_SUPPORT) 1187 if (SOC_IS_TRX(unit)) { 1188 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1189 BUS0_1_SELf, ((phy_id & 0x20) ? 1 : 0)); 1190 phy_id &= (~0x20); 1191 1192 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, 1193 BUS2_SELf, ((phy_id & 0x40) ? 1 : 0)); 1194 phy_id &= (~0x40); 1195 } else 1196 #endif 1197 { 1198 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, HG_SELf, 1199 ((phy_id & 0x40) ? 1 : 0)); 1200 phy_id &= (~0x40); 1201 } 1202 } 1203 1204 soc_reg_field_set(unit, CMIC_RPE_MIIM_PARAMr, &phy_param, PHY_IDf, phy_id); 1205 phy_miim_addr = 0; 1206 soc_reg_field_set(unit, CMIC_RPE_MIIM_ADDRESSr, &phy_miim_addr, 1207 CLAUSE_45_DTYPEf, phy_devad); 1208 soc_reg_field_set(unit, CMIC_RPE_MIIM_ADDRESSr, &phy_miim_addr, 1209 CLAUSE_45_REGADRf, phy_reg_addr); 1210 1211 soc_pci_write(unit, CMIC_RPE_MIIM_ADDRESS_OFFSET, phy_miim_addr); 1212 soc_pci_write(unit, CMIC_RPE_MIIM_PARAM_OFFSET, phy_param); 1213 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 2); 1214 1215 /* Wait for completion using either the interrupt or polling method */ 1216 if (SOC_CONTROL(unit)->miimIntrEnb) { 1217 soc_cmicm_rcpu_intr0_enable(unit, IRQ_RCPU_MIIM_OP_DONE); 1218 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 1219 SOC_CONTROL(unit)->miimTimeout) != 0) { 1220 if ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 1221 CMIC_MIIM_OPN_DONE) == 0) { 1222 /* MIIM HW operation not complete */ 1223 rv = SOC_E_TIMEOUT; 1224 } else { 1225 /* MIIM HW operation complete but no intr received yet 1226 * Retry for MIIM Intr for busy system 1227 * before declaring timeout */ 1228 rv = SOC_E_TIMEOUT; 1229 while (miim_intr_retry_cnt) { 1230 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 1231 MIIM_INTR_RETRY_TIMEOUT) == 0) { 1232 rv = SOC_E_NONE; 1233 break; 1234 } 1235 miim_intr_retry_cnt--; 1236 } 1237 } 1238 } else { 1239 LOG_DEBUG(BSL_LS_SOC_MIIM, 1240 (BSL_META_U(unit, 1241 " Interrupt received\n"))); 1242 } 1243 1244 soc_cmicm_rcpu_intr0_disable(unit, IRQ_RCPU_MIIM_OP_DONE); 1245 } else { 1246 soc_timeout_t to; 1247 1248 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, 250); 1249 1250 while ((soc_pci_read(unit, CMIC_RPE_MIIM_STAT_OFFSET) & 1251 CMIC_MIIM_OPN_DONE) == 0) { 1252 if (soc_timeout_check(&to)) { 1253 rv = SOC_E_TIMEOUT; 1254 break; 1255 } 1256 } 1257 1258 if (rv == SOC_E_NONE) { 1259 LOG_DEBUG(BSL_LS_SOC_MIIM, 1260 (BSL_META_U(unit, 1261 " Done in %d polls\n"), to.polls)); 1262 } 1263 1264 soc_pci_write(unit, CMIC_RPE_MIIM_CTRL_OFFSET, 0); 1265 } 1266 1267 if (rv == SOC_E_TIMEOUT) { 1268 LOG_ERROR(BSL_LS_SOC_COMMON, 1269 (BSL_META_U(unit, 1270 "MiimTimeOut:soc_rcpu_miimc45_read, " 1271 "timeout (id=0x%02x addr=0x%02x)\n"), 1272 phy_id, phy_reg_addr)); 1273 SOC_CONTROL(unit)->stat.err_mii_tmo++; 1274 } else { 1275 *phy_rd_data = (uint16)soc_pci_read(unit, CMIC_RPE_MIIM_READ_DATA_OFFSET); 1276 1277 LOG_VERBOSE(BSL_LS_SOC_MIIM, 1278 (BSL_META_U(unit, 1279 "soc_rcpu_miimc45_read: read data=0x%04x\n"), *phy_rd_data)); 1280 } 1281 1282 /* Release linkscan pause and MIIM lock */ 1283 MIIM_UNLOCK(unit); 1284 1285 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 1286 soc_linkscan_continue(unit); 1287 } 1288 } 1289 1290 return rv; 1291 1292 } 1293 #endif /* defined(BCM_RCPU_SUPPORT) && defined(BCM_CMICM_SUPPORT) */ 1294 1295 /* 1296 * Function: 1297 * soc_esw_miim_write 1298 * Purpose: 1299 * New interface to write a value to a MIIM register. 1300 * Parameters: 1301 * unit - StrataSwitch Unit #. 1302 * phy_id - Phy ID to write (MIIM address) 1303 * phy_reg_addr - PHY register to write 1304 * phy_wr_data - Data to write. 1305 * Returns: 1306 * SOC_E_XXX 1307 * Notes: 1308 * Added to have the same interface for PHY register access among 1309 * ESW 1310 */ 1311 int 1312 soc_esw_miim_write(int unit, uint32 phy_id, 1313 uint32 phy_reg_addr, uint16 phy_wr_data) 1314 { 1315 return soc_miim_write(unit, (uint16)phy_id, 1316 (uint16)phy_reg_addr, phy_wr_data); 1317 } 1318 1319 /* 1320 * Function: 1321 * soc_esw_miim_read 1322 * Purpose: 1323 * New interface to read a value from a MIIM register. 1324 * Parameters: 1325 * unit - StrataSwitch Unit #. 1326 * phy_id - Phy ID to write (MIIM address) 1327 * phy_reg_addr - PHY register to write 1328 * phy_rd_data - Data read. 1329 * Returns: 1330 * SOC_E_XXX 1331 * Notes: 1332 * Added to have the same interface for PHY register access among 1333 * ESW 1334 */ 1335 int 1336 soc_esw_miim_read(int unit, uint32 phy_id, 1337 uint32 phy_reg_addr, uint16 *phy_rd_data) 1338 { 1339 return soc_miim_read(unit, (uint16)phy_id, 1340 (uint16)phy_reg_addr, phy_rd_data); 1341 } 1342 1343 /* 1344 * Function: 1345 * soc_miim_modify 1346 * Purpose: 1347 * Modify a value from an MII register. 1348 * Parameters: 1349 * unit - StrataSwitch Unit #. 1350 * phy_id - Phy ID to write (MIIM address) 1351 * phy_reg_addr - PHY register to write 1352 * phy_rd_data - 16bit data to write into 1353 * phy_rd_mask - 16bit mask to indicate the bits to modify. 1354 * Returns: 1355 * SOC_E_XXX 1356 * Notes: 1357 */ 1358 1359 int 1360 soc_miim_modify(int unit, uint16 phy_id, uint16 phy_reg_addr, 1361 uint16 phy_rd_data, uint16 phy_rd_mask) 1362 { 1363 uint16 tmp, otmp; 1364 1365 phy_rd_data = phy_rd_data & phy_rd_mask; 1366 1367 SOC_IF_ERROR_RETURN 1368 (soc_miim_read(unit, phy_id, phy_reg_addr, &tmp)); 1369 otmp = tmp; 1370 tmp &= ~(phy_rd_mask); 1371 tmp |= phy_rd_data; 1372 1373 if (otmp != tmp) { 1374 SOC_IF_ERROR_RETURN 1375 (soc_miim_write(unit, phy_id, phy_reg_addr, tmp)); 1376 } 1377 return SOC_E_NONE; 1378 } 1379 1380 /* 1381 * Function: 1382 * soc_esw_miimc45_write 1383 * Purpose: 1384 * Write a value from an MII register. 1385 * Parameters: 1386 * unit - StrataSwitch Unit #. 1387 * phy_id - Phy ID to write (MIIM address) 1388 * phy_reg_addr - PHY register to write (Encoded with PMA/PMD, PCS, PHY XS) 1389 * phy_rd_data - 16bit data to write into 1390 * Returns: 1391 * SOC_E_XXX 1392 * Notes: 1393 */ 1394 int 1395 soc_esw_miimc45_write(int unit, uint32 phy_id, 1396 uint32 phy_reg_addr, uint16 phy_wr_data) 1397 { 1398 uint8 dev_addr; 1399 uint16 reg_addr; 1400 1401 dev_addr = SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr); 1402 reg_addr = SOC_PHY_CLAUSE45_REGAD(phy_reg_addr); 1403 1404 return soc_miimc45_write(unit, (uint16)phy_id, dev_addr, 1405 reg_addr, phy_wr_data); 1406 } 1407 1408 /* 1409 * Function: 1410 * soc_esw_miimc45_write 1411 * Purpose: 1412 * Write a value from an MII register. 1413 * Parameters: 1414 * unit - StrataSwitch Unit #. 1415 * phy_id - Phy ID to write (MIIM address) 1416 * phy_reg_addr - PHY register to write (Encoded with PMA/PMD, PCS, PHY XS) 1417 * phy_rd_data - 16bit data to write into 1418 * Returns: 1419 * SOC_E_XXX 1420 * Notes: 1421 */ 1422 int 1423 soc_esw_miimc45_read(int unit, uint32 phy_id, 1424 uint32 phy_reg_addr, uint16 *phy_rd_data) 1425 { 1426 uint8 dev_addr; 1427 uint16 reg_addr; 1428 1429 dev_addr = SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr); 1430 reg_addr = SOC_PHY_CLAUSE45_REGAD(phy_reg_addr); 1431 1432 return soc_miimc45_read(unit, (uint16)phy_id, dev_addr, 1433 reg_addr, phy_rd_data); 1434 } 1435 1436 /* 1437 * Function: 1438 * soc_esw_miimc45_data_write 1439 * Purpose: 1440 * Write a value to the present MII register without a address cycle. 1441 * Parameters: 1442 * unit - StrataSwitch Unit #. 1443 * phy_id - Phy ID to write (MIIM address) 1444 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 1445 * phy_wr_data - 16 bit data for write 1446 * Returns: 1447 * SOC_E_XXX 1448 * Notes: 1449 */ 1450 int 1451 soc_esw_miimc45_data_write(int unit, uint32 phy_id, 1452 uint8 phy_devad, uint16 phy_wr_data) 1453 { 1454 uint8 dev_addr; 1455 uint16 reg_addr; 1456 1457 dev_addr = (phy_devad & ~MIIM_CYCLE_C45_MASK) | MIIM_CYCLE_C45_WR; 1458 reg_addr = 0; 1459 1460 return soc_miimc45_write(unit, (uint16)phy_id, dev_addr, 1461 reg_addr, phy_wr_data); 1462 } 1463 1464 /* 1465 * Function: 1466 * soc_esw_miimc45_data_read 1467 * Purpose: 1468 * Read a value from the present MII register without a address cycle. 1469 * Parameters: 1470 * unit - StrataSwitch Unit #. 1471 * phy_id - Phy ID to write (MIIM address) 1472 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 1473 * phy_rd_data - point to 16 bit data buffer 1474 * Returns: 1475 * SOC_E_XXX 1476 * Notes: 1477 */ 1478 int 1479 soc_esw_miimc45_data_read(int unit, uint32 phy_id, 1480 uint8 phy_devad, uint16 *phy_rd_data) 1481 { 1482 uint8 dev_addr; 1483 uint16 reg_addr; 1484 1485 dev_addr = (phy_devad & ~MIIM_CYCLE_C45_MASK) | MIIM_CYCLE_C45_RD; 1486 reg_addr = 0; 1487 1488 return soc_miimc45_read(unit, (uint16)phy_id, dev_addr, 1489 reg_addr, phy_rd_data); 1490 } 1491 1492 /* 1493 * Function: 1494 * soc_esw_miimc45_addr_write 1495 * Purpose: 1496 * Write the address register with a new address to access. 1497 * Parameters: 1498 * unit - StrataSwitch Unit #. 1499 * phy_id - Phy ID to write (MIIM address) 1500 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 1501 * phy_rd_data - 16 bit register address 1502 * Returns: 1503 * SOC_E_XXX 1504 * Notes: 1505 */ 1506 int 1507 soc_esw_miimc45_addr_write(int unit, uint32 phy_id, 1508 uint8 phy_devad, uint16 phy_ad_data) 1509 { 1510 uint8 dev_addr; 1511 uint16 reg_addr; 1512 1513 dev_addr = (phy_devad & ~MIIM_CYCLE_C45_MASK) | MIIM_CYCLE_C45_WR_AD; 1514 reg_addr = phy_ad_data; 1515 1516 return soc_miimc45_write(unit, (uint16)phy_id, dev_addr, 1517 reg_addr, 0); 1518 } 1519 1520 /* 1521 * Function: 1522 * soc_esw_miimc45_post_read 1523 * Purpose: 1524 * Read a value from the present MII register and increase register addr. 1525 * Parameters: 1526 * unit - StrataSwitch Unit #. 1527 * phy_id - Phy ID to write (MIIM address) 1528 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 1529 * phy_rd_data - point to 16 bit data buffer 1530 * Returns: 1531 * SOC_E_XXX 1532 * Notes: 1533 */ 1534 int 1535 soc_esw_miimc45_post_read(int unit, uint32 phy_id, 1536 uint8 phy_devad, uint16 *phy_rd_data) 1537 { 1538 uint8 dev_addr; 1539 uint16 reg_addr; 1540 1541 dev_addr = (phy_devad & ~MIIM_CYCLE_C45_MASK) | MIIM_CYCLE_C45_RD_ADINC; 1542 reg_addr = 0; 1543 1544 return soc_miimc45_read(unit, (uint16)phy_id, dev_addr, 1545 reg_addr, phy_rd_data); 1546 } 1547 1548 /* 1549 * Function: 1550 * soc_miimc45_modify 1551 * Purpose: 1552 * Modify a value from an MII register. 1553 * Parameters: 1554 * unit - StrataSwitch Unit #. 1555 * phy_id - Phy ID to write (MIIM address) 1556 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 1557 * phy_reg_addr - PHY register to write 1558 * phy_rd_data - 16bit data to write into 1559 * phy_rd_mask - 16bit mask to indicate the bits to modify. 1560 * Returns: 1561 * SOC_E_XXX 1562 * Notes: 1563 */ 1564 1565 int 1566 soc_miimc45_modify(int unit, uint16 phy_id, uint8 phy_devad, 1567 uint16 phy_reg_addr, uint16 phy_rd_data, uint16 phy_rd_mask) 1568 { 1569 uint16 tmp = 0, otmp; 1570 1571 phy_rd_data = phy_rd_data & phy_rd_mask; 1572 1573 SOC_IF_ERROR_RETURN 1574 (soc_miimc45_read(unit, phy_id, phy_devad, phy_reg_addr, &tmp)); 1575 otmp = tmp; 1576 tmp &= ~(phy_rd_mask); 1577 tmp |= phy_rd_data; 1578 1579 if (otmp != tmp) { 1580 SOC_IF_ERROR_RETURN 1581 (soc_miimc45_write(unit, phy_id, phy_devad, phy_reg_addr, tmp)); 1582 } 1583 return SOC_E_NONE; 1584 } 1585 1586 /* 1587 * Customer specific MDIO wrapper support 1588 * 1589 * Some customers of the SDK wish to wrap the underlying MDIO access 1590 * routines (both clause 22 and clasue 45) with customer specific 1591 * functions that may provide an alternate access method, some predicate 1592 * controls on whether actual operations occur, or some translation 1593 * mechanisms. 1594 * 1595 * The method discussed here is an interim mechanism that is sufficient 1596 * for release to selected customers. A more extensible long term 1597 * mechanism will be defined in a future SDK release. This method will 1598 * work for Enterprise Switch (XGS) operations but may not work for 1599 * other device families. 1600 * 1601 * 1. Replace the file $SDK/soc/common/miim.c with this file. 1602 * It moves the basic miim access functions to the end of the file 1603 * and provides mechanism to rename them to _soc_miim*. 1604 * 2. Compile the entire SDK with the following defines on the command line: 1605 * -Dsoc_miim_read=cust_miim_read 1606 * -Dsoc_miim_write=cust_miim_write 1607 * -Dsoc_miimc45_read=cust_miimc45_read 1608 * -Dsoc_miimc45_write=cust_miic45_write 1609 * 3. Provide implementation of the cust_miim* functions. 1610 * They are defined identically to the soc_miim* functions below: 1611 * int cust_miim_write(int unit, uint8 phy_id, 1612 * uint8 phy_reg_addr, uint16 phy_wr_data) 1613 * int cust_miim_read(int unit, uint8 phy_id, 1614 * uint8 phy_reg_addr, uint16 *phy_rd_data) 1615 * int cust_miimc45_write(int unit, uint8 phy_id, uint8 phy_devad, 1616 * uint16 phy_reg_addr, uint16 phy_wr_data) 1617 * int cust_miimc45_read(int unit, uint8 phy_id, uint8 phy_devad, 1618 * uint16 phy_reg_addr, uint16 *phy_rd_data) 1619 * 4. If the cust_miim* functions need to access the original defintions 1620 * of the soc_miim* functions, they need to refer to them as _soc_miim* 1621 * and provide extern definitions of those functions: 1622 * extern int _soc_miim_write(int unit, uint8 phy_id, 1623 * uint8 phy_reg_addr, uint16 phy_wr_data); 1624 * extern int _soc_miim_read(int unit, uint8 phy_id, 1625 * uint8 phy_reg_addr, uint16 *phy_rd_data); 1626 * extern int _soc_miimc45_write(int unit, uint8 phy_id, uint8 phy_devad, 1627 * uint16 phy_reg_addr, uint16 phy_wr_data); 1628 * extern int _soc_miimc45_read(int unit, uint8 phy_id, uint8 phy_devad, 1629 * uint16 phy_reg_addr, uint16 *phy_rd_data); 1630 */ 1631 #ifdef soc_miim_read 1632 #undef soc_miim_read 1633 #define soc_miim_read _soc_miim_read 1634 #endif 1635 #ifdef soc_miim_write 1636 #undef soc_miim_write 1637 #define soc_miim_write _soc_miim_write 1638 #endif 1639 #ifdef soc_miimc45_read 1640 #undef soc_miimc45_read 1641 #define soc_miimc45_read _soc_miimc45_read 1642 #endif 1643 #ifdef soc_miimc45_write 1644 #undef soc_miimc45_write 1645 #define soc_miimc45_write _soc_miimc45_write 1646 #endif 1647 1648 /* 1649 * Function: 1650 * soc_miim_write 1651 * Purpose: 1652 * Write a value to a MIIM register. 1653 * Parameters: 1654 * unit - StrataSwitch Unit #. 1655 * phy_id - Phy ID to write (MIIM address) 1656 * phy_reg_addr - PHY register to write 1657 * phy_wr_data - Data to write. 1658 * Returns: 1659 * SOC_E_XXX 1660 * Notes: 1661 * Temporarily disables auto link scan if it was enabled. The MIIM 1662 * registers are locked during the operation to prevent multiple 1663 * tasks from trying to access PHY registers simultaneously. 1664 */ 1665 1666 int 1667 soc_miim_write(int unit, uint16 phy_id, 1668 uint8 phy_reg_addr, uint16 phy_wr_data) 1669 { 1670 int rv = SOC_E_NONE; 1671 #if defined(BCM_ESW_SUPPORT) || defined (BCM_DFE_SUPPORT) 1672 int clause45; 1673 uint32 phy_param; 1674 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 1675 #ifdef BCM_CMICM_SUPPORT 1676 int cmc = SOC_PCI_CMC(unit); 1677 #endif 1678 #endif 1679 1680 #if defined(BCM_ESW_SUPPORT) || defined (BCM_DFE_SUPPORT) 1681 assert(!sal_int_context()); 1682 1683 LOG_VERBOSE(BSL_LS_SOC_MIIM, 1684 (BSL_META_U(unit, 1685 "soc_miim_write: id=0x%02x addr=0x%02x data=0x%04x\n"), 1686 phy_id, phy_reg_addr, phy_wr_data)); 1687 1688 clause45 = soc_feature(unit, soc_feature_phy_cl45); 1689 1690 #ifdef BCM_CMICX_SUPPORT 1691 if (soc_feature(unit, soc_feature_cmicx)) { 1692 return soc_cmicx_miim_operation(unit, TRUE, SOC_CLAUSE_22, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, phy_id, 1693 phy_reg_addr, &phy_wr_data); 1694 } 1695 #endif /* BCM_CMICX_SUPPORT */ 1696 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_CMICM_SUPPORT) 1697 /* 1698 * Trident Switch And Later 1699 * internal select bit 25 1700 * BUS_ID bit 22-24 1701 * C45_SEL bit 21 1702 */ 1703 if (SOC_IS_TD_TT(unit) || soc_feature(unit, soc_feature_cmicm)) { 1704 1705 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 1706 1707 /* set 5-bit PHY MDIO address */ 1708 phy_param = (uint32)phy_wr_data | 1709 (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 1710 1711 /* select internal MDIO bus if set */ 1712 if (phy_id & 0x80) { /* Internal/External select */ 1713 #if defined(BCM_CMICDV3_SUPPORT) 1714 /* 1715 * Apache and Tomahawk2 Switches And Later 1716 * internal select bit 26 1717 * BUS_ID bit 22-25 1718 * C45_SEL bit 21 1719 * See CMIC_CMC0_MIIM_PARAM register. 1720 */ 1721 if (soc_feature(unit, soc_feature_cmicd_v3)) { 1722 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 10)); 1723 } else 1724 #endif /* BCM_CMICDV3_SUPPORT */ 1725 { 1726 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 9)); 1727 } 1728 } 1729 1730 /* set MDIO bus number */ 1731 phy_param |= (bus_sel << (MIIM_PARAM_ID_OFFSET + 6)); 1732 } else 1733 #endif 1734 #ifdef BCM_SHADOW_SUPPORT 1735 if (SOC_IS_SHADOW(unit)) { 1736 1737 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 1738 1739 /* set 5-bit PHY MDIO address */ 1740 phy_param = (uint32)phy_wr_data | 1741 (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 1742 1743 /* select internal MDIO bus if set */ 1744 if (phy_id & 0x80) { /* Internal/External select */ 1745 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 9)); 1746 } 1747 1748 /* set MDIO bus number */ 1749 phy_param |= (bus_sel << (MIIM_PARAM_ID_OFFSET + 6)); 1750 } else 1751 #endif /* BCM_SHADOW_SUPPORT */ 1752 1753 #ifdef BCM_TRX_SUPPORT 1754 1755 if (SOC_IS_TRX(unit)) { 1756 int bus_sel = (phy_id & 0x60) >> 5; 1757 1758 phy_param = (uint32)phy_wr_data | 1759 (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 1760 1761 if (phy_id & 0x80) { /* Internal/External select */ 1762 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 7)); 1763 } 1764 if (bus_sel == 1) { 1765 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 6)); 1766 } else if (bus_sel == 2) { 1767 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 8)); 1768 } 1769 } else 1770 #endif /* BCM_TRX_SUPPORT */ 1771 { 1772 phy_param = ((uint32)phy_id << MIIM_PARAM_ID_OFFSET | 1773 (uint32)phy_wr_data); 1774 } 1775 1776 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 1777 soc_linkscan_pause(unit); 1778 } 1779 MIIM_LOCK(unit); 1780 1781 /* Write parameter register and tell CMIC to start */ 1782 1783 /* Clause 45 support changes Clause 22 access method */ 1784 if (clause45) { 1785 #ifdef BCM_CMICM_SUPPORT 1786 if(soc_feature(unit, soc_feature_cmicm)) { 1787 soc_pci_write(unit, CMIC_CMCx_MIIM_ADDRESS_OFFSET(cmc), phy_reg_addr); 1788 } else 1789 #endif 1790 { 1791 WRITE_CMIC_MIIM_ADDRESSr(unit, phy_reg_addr); 1792 } 1793 } else { 1794 phy_param |= (uint32)phy_reg_addr << MIIM_PARAM_REG_ADDR_OFFSET; 1795 } 1796 1797 #ifdef BCM_CMICM_SUPPORT 1798 if(soc_feature(unit, soc_feature_cmicm)) { 1799 soc_pci_write(unit, CMIC_CMCx_MIIM_PARAM_OFFSET(cmc), phy_param); 1800 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 1); 1801 } else 1802 #endif 1803 { 1804 soc_pci_write(unit, CMIC_MIIM_PARAM, phy_param); 1805 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_WR_START_SET); 1806 } 1807 1808 /* Wait for completion using either the interrupt or polling method */ 1809 1810 if (SOC_CONTROL(unit)->miimIntrEnb) { 1811 #ifdef BCM_CMICM_SUPPORT 1812 if(soc_feature(unit, soc_feature_cmicm)) { 1813 soc_cmicm_intr0_enable(unit, IRQ_CMCx_MIIM_OP_DONE); 1814 } else 1815 #endif 1816 { 1817 soc_intr_enable(unit, IRQ_MIIM_OP_DONE); 1818 } 1819 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 1820 SOC_CONTROL(unit)->miimTimeout) != 0) { 1821 #ifdef BCM_CMICM_SUPPORT 1822 if(soc_feature(unit, soc_feature_cmicm)) { 1823 if ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 1824 CMIC_MIIM_OPN_DONE) == 0) { 1825 /* MIIM HW operation not complete */ 1826 rv = SOC_E_TIMEOUT; 1827 } else { 1828 /* MIIM HW operation complete but no intr received yet 1829 * Retry for MIIM Intr for busy system 1830 * before declaring timeout */ 1831 rv = SOC_E_TIMEOUT; 1832 while (miim_intr_retry_cnt) { 1833 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 1834 MIIM_INTR_RETRY_TIMEOUT) == 0) { 1835 rv = SOC_E_NONE; 1836 break; 1837 } 1838 miim_intr_retry_cnt--; 1839 } 1840 } 1841 } else 1842 #endif 1843 { 1844 if ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & SC_MIIM_OP_DONE_TST) == 0) { 1845 /* MIIM HW operation not complete */ 1846 rv = SOC_E_TIMEOUT; 1847 } else { 1848 /* MIIM HW operation complete but no intr received yet 1849 * Retry for MIIM Intr for busy system 1850 * before declaring timeout */ 1851 rv = SOC_E_TIMEOUT; 1852 while (miim_intr_retry_cnt) { 1853 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 1854 MIIM_INTR_RETRY_TIMEOUT) == 0) { 1855 rv = SOC_E_NONE; 1856 break; 1857 } 1858 miim_intr_retry_cnt--; 1859 } 1860 } 1861 } 1862 } else { 1863 LOG_DEBUG(BSL_LS_SOC_MIIM, 1864 (BSL_META_U(unit, 1865 " Interrupt received\n"))); 1866 } 1867 1868 #ifdef BCM_CMICM_SUPPORT 1869 if(soc_feature(unit, soc_feature_cmicm)) { 1870 soc_cmicm_intr0_disable(unit, IRQ_CMCx_MIIM_OP_DONE); 1871 } else 1872 #endif 1873 { 1874 soc_intr_disable(unit, IRQ_MIIM_OP_DONE); 1875 } 1876 } else { 1877 soc_timeout_t to; 1878 1879 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, MIIM_POLL_TIMEOUT); 1880 1881 #ifdef BCM_CMICM_SUPPORT 1882 if(soc_feature(unit, soc_feature_cmicm)) { 1883 while ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 1884 CMIC_MIIM_OPN_DONE) == 0) { 1885 if (soc_timeout_check(&to)) { 1886 rv = SOC_E_TIMEOUT; 1887 break; 1888 } 1889 } 1890 } else 1891 #endif 1892 { 1893 while ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & 1894 SC_MIIM_OP_DONE_TST) == 0) { 1895 if (soc_timeout_check(&to)) { 1896 rv = SOC_E_TIMEOUT; 1897 break; 1898 } 1899 } 1900 } 1901 if (rv == SOC_E_NONE) { 1902 LOG_DEBUG(BSL_LS_SOC_MIIM, 1903 (BSL_META_U(unit, 1904 " Done in %d polls\n"), to.polls)); 1905 if (soc_feature(unit, soc_feature_wh2_miim_delay)) { 1906 sal_udelay(10); 1907 } 1908 } 1909 #ifdef BCM_CMICM_SUPPORT 1910 if(soc_feature(unit, soc_feature_cmicm)) { 1911 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 0); 1912 } else 1913 #endif 1914 { 1915 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_OP_DONE_CLR); 1916 } 1917 } 1918 if (rv == SOC_E_TIMEOUT) { 1919 LOG_ERROR(BSL_LS_SOC_COMMON, 1920 (BSL_META_U(unit, 1921 "MiimTimeOut:soc_miim_write, " 1922 "timeout (id=0x%02x addr=0x%02x data=0x%04x)\n"), 1923 phy_id, phy_reg_addr, phy_wr_data)); 1924 SOC_CONTROL(unit)->stat.err_mii_tmo++; 1925 } 1926 1927 /* Release linkscan pause and MIIM lock */ 1928 1929 MIIM_UNLOCK(unit); 1930 1931 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 1932 soc_linkscan_continue(unit); 1933 } 1934 #endif 1935 return rv; 1936 1937 } 1938 1939 /* 1940 * Function: 1941 * soc_miim_read 1942 * Purpose: 1943 * Read a value from an MII register. 1944 * Parameters: 1945 * unit - StrataSwitch Unit #. 1946 * phy_id - Phy ID to write (MIIM address) 1947 * phy_reg_addr - PHY register to write 1948 * phy_rd_data - 16bit data to write into 1949 * Returns: 1950 * SOC_E_XXX 1951 * Notes: 1952 * Temporarily disables auto link scan if it was enabled. The MIIM 1953 * registers are locked during the operation to prevent multiple 1954 * tasks from trying to access PHY registers simultaneously. 1955 */ 1956 1957 int 1958 soc_miim_read(int unit, uint16 phy_id, 1959 uint8 phy_reg_addr, uint16 *phy_rd_data) 1960 { 1961 int rv = SOC_E_NONE; 1962 #if defined(BCM_ESW_SUPPORT) || defined(BCM_DFE_SUPPORT) 1963 int clause45; 1964 uint32 phy_param; 1965 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 1966 #ifdef BCM_CMICM_SUPPORT 1967 int cmc = SOC_PCI_CMC(unit); 1968 #endif 1969 #endif 1970 1971 assert(!sal_int_context()); 1972 assert(phy_rd_data); 1973 1974 #if defined(BCM_ESW_SUPPORT) || defined(BCM_DFE_SUPPORT) 1975 LOG_VERBOSE(BSL_LS_SOC_MIIM, 1976 (BSL_META_U(unit, 1977 "soc_miim_read: id=0x%02x addr=0x%02x "), 1978 phy_id, phy_reg_addr)); 1979 1980 clause45 = soc_feature(unit, soc_feature_phy_cl45); 1981 1982 #ifdef BCM_CMICX_SUPPORT 1983 if (soc_feature(unit, soc_feature_cmicx)) { 1984 return soc_cmicx_miim_operation(unit, FALSE, SOC_CLAUSE_22, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, phy_id, 1985 phy_reg_addr, phy_rd_data); 1986 } 1987 #endif /* BCM_CMICX_SUPPORT */ 1988 1989 #if defined (BCM_CMICDV3_SUPPORT) 1990 /* 1991 * Apache Switch And Later 1992 * internal select bit 26 1993 * BUS_ID bit 22-25 1994 * C45_SEL bit 21 1995 */ 1996 if (soc_feature(unit, soc_feature_cmicd_v3)) { 1997 1998 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 1999 2000 /* set 5-bit PHY MDIO address */ 2001 phy_param = (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 2002 2003 /* select internal MDIO bus if set */ 2004 if (phy_id & 0x80) { /* Internal/External select */ 2005 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 10)); 2006 } 2007 2008 /* set MDIO bus number */ 2009 phy_param |= (bus_sel << (MIIM_PARAM_ID_OFFSET + 6)); 2010 } else 2011 2012 #endif 2013 2014 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_CMICM_SUPPORT) 2015 /* 2016 * Trident Switch And Later 2017 * internal select bit 25 2018 * BUS_ID bit 22-24 2019 * C45_SEL bit 21 2020 */ 2021 if (SOC_IS_TD_TT(unit) || soc_feature(unit, soc_feature_cmicm)) { 2022 2023 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 2024 2025 /* set 5-bit PHY MDIO address */ 2026 phy_param = (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 2027 2028 /* select internal MDIO bus if set */ 2029 if (phy_id & 0x80) { /* Internal/External select */ 2030 #if defined(BCM_CMICDV3_SUPPORT) 2031 /* 2032 * Apache and Tomahawk2 Switches And Later 2033 * internal select bit 26 2034 * BUS_ID bit 22-25 2035 * C45_SEL bit 21 2036 * See CMIC_CMC0_MIIM_PARAM register. 2037 */ 2038 if (soc_feature(unit, soc_feature_cmicd_v3)) { 2039 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 10)); 2040 } else 2041 #endif /* BCM_CMICDV3_SUPPORT */ 2042 { 2043 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 9)); 2044 } 2045 } 2046 2047 /* set MDIO bus number */ 2048 phy_param |= (bus_sel << (MIIM_PARAM_ID_OFFSET + 6)); 2049 } else 2050 #endif 2051 #ifdef BCM_SHADOW_SUPPORT 2052 /* 2053 * Shadow device 2054 * internal select bit 25 2055 * BUS_ID bit 22-24 2056 * C45_SEL bit 21 2057 */ 2058 if (SOC_IS_SHADOW(unit)) { 2059 2060 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 2061 2062 /* set 5-bit PHY MDIO address */ 2063 phy_param = (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 2064 2065 /* select internal MDIO bus if set */ 2066 if (phy_id & 0x80) { /* Internal/External select */ 2067 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 9)); 2068 } 2069 2070 /* set MDIO bus number */ 2071 phy_param |= (bus_sel << (MIIM_PARAM_ID_OFFSET + 6)); 2072 } else 2073 #endif /* BCM_SHADOW_SUPPORT */ 2074 2075 2076 #ifdef BCM_TRX_SUPPORT 2077 2078 if (SOC_IS_TRX(unit)) { 2079 int bus_sel = (phy_id & 0x60) >> 5; 2080 2081 phy_param = (((uint32)phy_id & 0x1f) << MIIM_PARAM_ID_OFFSET); 2082 2083 if (phy_id & 0x80) { /* Internal/External select */ 2084 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 7)); 2085 } 2086 if (bus_sel == 1) { 2087 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 6)); 2088 } else if (bus_sel == 2) { 2089 phy_param |= (1 << (MIIM_PARAM_ID_OFFSET + 8)); 2090 } 2091 } else 2092 #endif /* BCM_TRX_SUPPORT */ 2093 { 2094 phy_param = (uint32)phy_id << MIIM_PARAM_ID_OFFSET; 2095 } 2096 2097 /* Pause link scanning - and hold MIIM lock */ 2098 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 2099 soc_linkscan_pause(unit); 2100 } 2101 MIIM_LOCK(unit); 2102 2103 /* Write parameter register and tell CMIC to start */ 2104 2105 /* Clause 45 support changes Clause 22 access method */ 2106 if (clause45) { 2107 #ifdef BCM_CMICM_SUPPORT 2108 if(soc_feature(unit, soc_feature_cmicm)) { 2109 soc_pci_write(unit, CMIC_CMCx_MIIM_ADDRESS_OFFSET(cmc), phy_reg_addr); 2110 } else 2111 #endif 2112 { 2113 WRITE_CMIC_MIIM_ADDRESSr(unit, phy_reg_addr); 2114 } 2115 } else { 2116 phy_param |= (uint32)phy_reg_addr << MIIM_PARAM_REG_ADDR_OFFSET; 2117 } 2118 2119 #ifdef BCM_CMICM_SUPPORT 2120 if(soc_feature(unit, soc_feature_cmicm)) { 2121 soc_pci_write(unit, CMIC_CMCx_MIIM_PARAM_OFFSET(cmc), phy_param); 2122 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 2); 2123 } else 2124 #endif 2125 { 2126 soc_pci_write(unit, CMIC_MIIM_PARAM, phy_param); 2127 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_RD_START_SET); 2128 } 2129 2130 /* Wait for completion using either the interrupt or polling method */ 2131 2132 if (SOC_CONTROL(unit)->miimIntrEnb) { 2133 #ifdef BCM_CMICM_SUPPORT 2134 if(soc_feature(unit, soc_feature_cmicm)) { 2135 soc_cmicm_intr0_enable(unit, IRQ_CMCx_MIIM_OP_DONE); 2136 } else 2137 #endif 2138 { 2139 soc_intr_enable(unit, IRQ_MIIM_OP_DONE); 2140 } 2141 2142 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2143 SOC_CONTROL(unit)->miimTimeout) != 0) { 2144 #ifdef BCM_CMICM_SUPPORT 2145 if(soc_feature(unit, soc_feature_cmicm)) { 2146 if ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 2147 CMIC_MIIM_OPN_DONE) == 0) { 2148 /* MIIM HW operation not complete */ 2149 rv = SOC_E_TIMEOUT; 2150 } else { 2151 /* MIIM HW operation complete but no intr received yet 2152 * Retry for MIIM Intr for busy system 2153 * before declaring timeout */ 2154 rv = SOC_E_TIMEOUT; 2155 while (miim_intr_retry_cnt) { 2156 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2157 MIIM_INTR_RETRY_TIMEOUT) == 0) { 2158 rv = SOC_E_NONE; 2159 break; 2160 } 2161 miim_intr_retry_cnt--; 2162 } 2163 } 2164 } else 2165 #endif 2166 { 2167 if ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & SC_MIIM_OP_DONE_TST) == 0) { 2168 /* MIIM HW operation not complete */ 2169 rv = SOC_E_TIMEOUT; 2170 } else { 2171 /* MIIM HW operation complete but no intr received yet 2172 * Retry for MIIM Intr for busy system 2173 * before declaring timeout */ 2174 rv = SOC_E_TIMEOUT; 2175 while (miim_intr_retry_cnt) { 2176 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2177 MIIM_INTR_RETRY_TIMEOUT) == 0) { 2178 rv = SOC_E_NONE; 2179 break; 2180 } 2181 miim_intr_retry_cnt--; 2182 } 2183 } 2184 } 2185 } else { 2186 LOG_DEBUG(BSL_LS_SOC_MIIM, 2187 (BSL_META_U(unit, 2188 " Interrupt received\n"))); 2189 } 2190 2191 #ifdef BCM_CMICM_SUPPORT 2192 if(soc_feature(unit, soc_feature_cmicm)) { 2193 soc_cmicm_intr0_disable(unit, IRQ_CMCx_MIIM_OP_DONE); 2194 } else 2195 #endif 2196 { 2197 soc_intr_disable(unit, IRQ_MIIM_OP_DONE); 2198 } 2199 } else { 2200 soc_timeout_t to; 2201 2202 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, MIIM_POLL_TIMEOUT); 2203 2204 #ifdef BCM_CMICM_SUPPORT 2205 if(soc_feature(unit, soc_feature_cmicm)) { 2206 while ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 2207 CMIC_MIIM_OPN_DONE) == 0) { 2208 if (soc_timeout_check(&to)) { 2209 rv = SOC_E_TIMEOUT; 2210 break; 2211 } 2212 } 2213 } else 2214 #endif 2215 { 2216 while ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & 2217 SC_MIIM_OP_DONE_TST) == 0) { 2218 if (soc_timeout_check(&to)) { 2219 rv = SOC_E_TIMEOUT; 2220 break; 2221 } 2222 } 2223 } 2224 2225 if (rv == SOC_E_NONE) { 2226 LOG_DEBUG(BSL_LS_SOC_MIIM, 2227 (BSL_META_U(unit, 2228 " Done in %d polls\n"), to.polls)); 2229 } 2230 #ifdef BCM_CMICM_SUPPORT 2231 if(soc_feature(unit, soc_feature_cmicm)) { 2232 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 0); 2233 } else 2234 #endif 2235 { 2236 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_OP_DONE_CLR); 2237 } 2238 } 2239 2240 if (rv == SOC_E_TIMEOUT) { 2241 LOG_ERROR(BSL_LS_SOC_COMMON, 2242 (BSL_META_U(unit, 2243 "MiimTimeOut:soc_miim_read, " 2244 "timeout (id=0x%02x addr=0x%02x)\n"), 2245 phy_id, phy_reg_addr)); 2246 SOC_CONTROL(unit)->stat.err_mii_tmo++; 2247 } else { 2248 #ifdef BCM_CMICM_SUPPORT 2249 if(soc_feature(unit, soc_feature_cmicm)) { 2250 *phy_rd_data = (uint16)soc_pci_read(unit, CMIC_CMCx_MIIM_READ_DATA_OFFSET(cmc)); 2251 } else 2252 #endif 2253 { 2254 *phy_rd_data = (uint16)soc_pci_read(unit, CMIC_MIIM_READ_DATA); 2255 } 2256 2257 LOG_VERBOSE(BSL_LS_SOC_MIIM, 2258 (BSL_META_U(unit, 2259 "data=0x%04x\n"), *phy_rd_data)); 2260 } 2261 2262 /* Release linkscan pause and MIIM lock */ 2263 2264 MIIM_UNLOCK(unit); 2265 2266 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 2267 soc_linkscan_continue(unit); 2268 } 2269 #endif 2270 return rv; 2271 2272 } 2273 2274 /* 2275 * Function: 2276 * __soc_miimc45_write 2277 * Purpose: 2278 * Write a value to a MIIM register. 2279 * Parameters: 2280 * unit - StrataSwitch Unit #. 2281 * phy_id - Phy ID to write (MIIM address) 2282 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 2283 * phy_reg_addr - PHY register to write 2284 * phy_wr_data - Data to write. 2285 * flags - flags altering the behavior of the function. 2286 * Returns: 2287 * SOC_E_XXX 2288 * Notes: 2289 * Temporarily disables auto link scan if it was enabled. The MIIM 2290 * registers are locked during the operation to prevent multiple 2291 * tasks from trying to access PHY registers simultaneously. 2292 */ 2293 2294 int 2295 __soc_miimc45_write(int unit, uint16 phy_id, uint8 phy_devad, 2296 uint16 phy_reg_addr, uint16 phy_wr_data, uint32 flags) 2297 { 2298 int rv = SOC_E_NONE; 2299 assert(!sal_int_context()); 2300 2301 if ((SOC_WARM_BOOT(unit)) && (phy_devad != 0x1e) && !(flags & MIIM_WB_C45)) { 2302 return SOC_E_NONE; 2303 } 2304 2305 LOG_VERBOSE(BSL_LS_SOC_MIIM, 2306 (BSL_META_U(unit, 2307 "__soc_miimc45_write: id=0x%02x phy_devad=0x%02x " 2308 "addr=0x%02x data=0x%04x\n"), 2309 phy_id, phy_devad, phy_reg_addr, phy_wr_data)); 2310 2311 if (!soc_feature(unit, soc_feature_phy_cl45)) { 2312 return SOC_E_UNAVAIL; 2313 } 2314 #ifdef BCM_ESW_SUPPORT 2315 2316 if ((SOC_IS_RELOADING(unit)) && (phy_devad != 0x1e) && !(flags & MIIM_WB_C45)) { 2317 return SOC_E_NONE; 2318 } 2319 2320 #if defined(BCM_XGS3_SWITCH_SUPPORT) 2321 { 2322 uint32 phy_param; 2323 uint32 phy_miim_addr; 2324 uint32 cycle_type; 2325 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 2326 #ifdef BCM_CMICM_SUPPORT 2327 int cmc = SOC_PCI_CMC(unit); 2328 #endif 2329 #ifdef BCM_CMICX_SUPPORT 2330 if (soc_feature(unit, soc_feature_cmicx)) { 2331 return soc_cmicx_miim_operation(unit, TRUE, SOC_CLAUSE_45, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, phy_id, 2332 ((phy_devad << 16) | (phy_reg_addr & 0xFFFF)), &phy_wr_data); 2333 } 2334 #endif /* BCM_CMICX_SUPPORT */ 2335 /* Pause link scanning - and hold MIIM lock */ 2336 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 2337 soc_linkscan_pause(unit); 2338 } 2339 MIIM_LOCK(unit); 2340 2341 /* Write parameter registers and tell CMIC to start */ 2342 phy_param = 0; 2343 if (phy_devad & MIIM_CYCLE_C45_WR) { 2344 cycle_type = MIIM_CYCLE_C45_REG_WR; 2345 } else if (phy_devad & MIIM_CYCLE_C45_WR_AD) { 2346 cycle_type = MIIM_CYCLE_C45_REG_AD; 2347 } else { 2348 cycle_type = MIIM_CYCLE_AUTO; 2349 } 2350 phy_devad &= ~MIIM_CYCLE_C45_MASK; 2351 #ifdef BCM_CMICM_SUPPORT 2352 if(soc_feature(unit, soc_feature_cmicm)) { 2353 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, &phy_param, 2354 MIIM_CYCLEf, cycle_type); 2355 } else 2356 #endif 2357 { 2358 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2359 MIIM_CYCLEf, cycle_type); 2360 } 2361 if (phy_id & 0x80) { 2362 phy_id &= (~0x80); 2363 #ifdef BCM_CMICM_SUPPORT 2364 if(soc_feature(unit, soc_feature_cmicm)) { 2365 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, 2366 &phy_param, INTERNAL_SELf, 1); 2367 } else 2368 #endif 2369 { 2370 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, 2371 &phy_param, INTERNAL_SELf, 1); 2372 } 2373 } 2374 #if defined(BCM_XGS3_SWITCH_SUPPORT) 2375 if (soc_feature(unit, soc_feature_mdio_enhanced)) { 2376 #ifdef BCM_CMICM_SUPPORT 2377 if(soc_feature(unit, soc_feature_cmicm)) { 2378 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, 2379 &phy_param, C45_SELf, 1); 2380 } else 2381 #endif 2382 { 2383 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, 2384 &phy_param, C45_SELf, 1); 2385 } 2386 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_CMICM_SUPPORT) 2387 if (SOC_IS_TD_TT(unit) || soc_feature(unit, soc_feature_cmicm)) { 2388 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 2389 #ifdef BCM_CMICM_SUPPORT 2390 if(soc_feature(unit, soc_feature_cmicm)) { 2391 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, &phy_param, 2392 BUS_IDf, bus_sel); 2393 } else 2394 #endif 2395 { 2396 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2397 BUS_IDf, bus_sel); 2398 } 2399 phy_id &= ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 2400 } else 2401 #endif 2402 #if defined(BCM_SHADOW_SUPPORT) 2403 if (SOC_IS_SHADOW(unit)) { 2404 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 2405 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2406 BUS_IDf, bus_sel); 2407 phy_id &= ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 2408 } else 2409 #endif 2410 #if defined(BCM_TRX_SUPPORT) 2411 if (SOC_IS_TRX(unit)) { 2412 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2413 BUS0_1_SELf, ((phy_id & 0x20) ? 1 : 0)); 2414 phy_id &= (~0x20); 2415 2416 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2417 BUS2_SELf, ((phy_id & 0x40) ? 1 : 0)); 2418 phy_id &= (~0x40); 2419 } else 2420 #endif /* BCM_TRX_SUPPORT */ 2421 { 2422 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, HG_SELf, 2423 ((phy_id & 0x40) ? 1 : 0)); 2424 phy_id &= (~0x40); 2425 } 2426 } 2427 #endif /* BCM_XGS3_SWITCH_SUPPORT */ 2428 2429 #ifdef BCM_CMICM_SUPPORT 2430 if(soc_feature(unit, soc_feature_cmicm)) { 2431 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, &phy_param, PHY_IDf, phy_id); 2432 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, &phy_param, 2433 PHY_DATAf, phy_wr_data); 2434 phy_miim_addr = 0; 2435 soc_reg_field_set(unit, CMIC_CMC0_MIIM_ADDRESSr, &phy_miim_addr, 2436 CLAUSE_45_DTYPEf, phy_devad); 2437 soc_reg_field_set(unit, CMIC_CMC0_MIIM_ADDRESSr, &phy_miim_addr, 2438 CLAUSE_45_REGADRf, phy_reg_addr); 2439 } else 2440 #endif 2441 { 2442 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, PHY_IDf, phy_id); 2443 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2444 PHY_DATAf, phy_wr_data); 2445 phy_miim_addr = 0; 2446 soc_reg_field_set(unit, CMIC_MIIM_ADDRESSr, &phy_miim_addr, 2447 CLAUSE_45_DTYPEf, phy_devad); 2448 soc_reg_field_set(unit, CMIC_MIIM_ADDRESSr, &phy_miim_addr, 2449 CLAUSE_45_REGADRf, phy_reg_addr); 2450 } 2451 #ifdef BCM_CMICM_SUPPORT 2452 if(soc_feature(unit, soc_feature_cmicm)) { 2453 soc_pci_write(unit, CMIC_CMCx_MIIM_ADDRESS_OFFSET(cmc), phy_miim_addr); 2454 soc_pci_write(unit, CMIC_CMCx_MIIM_PARAM_OFFSET(cmc), phy_param); 2455 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 1); 2456 } else 2457 #endif 2458 { 2459 WRITE_CMIC_MIIM_ADDRESSr(unit, phy_miim_addr); 2460 soc_pci_write(unit, CMIC_MIIM_PARAM, phy_param); 2461 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_WR_START_SET); 2462 } 2463 2464 /* Wait for completion using either the interrupt or polling method */ 2465 2466 if (SOC_CONTROL(unit)->miimIntrEnb) { 2467 #ifdef BCM_CMICM_SUPPORT 2468 if(soc_feature(unit, soc_feature_cmicm)) { 2469 soc_cmicm_intr0_enable(unit, IRQ_CMCx_MIIM_OP_DONE); 2470 } else 2471 #endif 2472 { 2473 soc_intr_enable(unit, IRQ_MIIM_OP_DONE); 2474 } 2475 2476 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2477 SOC_CONTROL(unit)->miimTimeout) != 0) { 2478 #ifdef BCM_CMICM_SUPPORT 2479 if(soc_feature(unit, soc_feature_cmicm)) { 2480 if ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 2481 CMIC_MIIM_OPN_DONE) == 0) { 2482 /* MIIM HW operation not complete */ 2483 rv = SOC_E_TIMEOUT; 2484 } else { 2485 /* MIIM HW operation complete but no intr received yet 2486 * Retry for MIIM Intr for busy system 2487 * before declaring timeout */ 2488 rv = SOC_E_TIMEOUT; 2489 while (miim_intr_retry_cnt) { 2490 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2491 MIIM_INTR_RETRY_TIMEOUT) == 0) { 2492 rv = SOC_E_NONE; 2493 break; 2494 } 2495 miim_intr_retry_cnt--; 2496 } 2497 } 2498 } else 2499 #endif 2500 { 2501 if ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & SC_MIIM_OP_DONE_TST) == 0) { 2502 /* MIIM HW operation not complete */ 2503 rv = SOC_E_TIMEOUT; 2504 } else { 2505 /* MIIM HW operation complete but no intr received yet 2506 * Retry for MIIM Intr for busy system 2507 * before declaring timeout */ 2508 rv = SOC_E_TIMEOUT; 2509 while (miim_intr_retry_cnt) { 2510 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2511 MIIM_INTR_RETRY_TIMEOUT) == 0) { 2512 rv = SOC_E_NONE; 2513 break; 2514 } 2515 miim_intr_retry_cnt--; 2516 } 2517 } 2518 } 2519 } else { 2520 LOG_DEBUG(BSL_LS_SOC_MIIM, 2521 (BSL_META_U(unit, 2522 " Interrupt received\n"))); 2523 } 2524 2525 #ifdef BCM_CMICM_SUPPORT 2526 if(soc_feature(unit, soc_feature_cmicm)) { 2527 soc_cmicm_intr0_disable(unit, IRQ_CMCx_MIIM_OP_DONE); 2528 } else 2529 #endif 2530 { 2531 soc_intr_disable(unit, IRQ_MIIM_OP_DONE); 2532 } 2533 } else { 2534 soc_timeout_t to; 2535 2536 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, MIIM_POLL_TIMEOUT); 2537 2538 #ifdef BCM_CMICM_SUPPORT 2539 if(soc_feature(unit, soc_feature_cmicm)) { 2540 while ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 2541 CMIC_MIIM_OPN_DONE) == 0) { 2542 if (soc_timeout_check(&to)) { 2543 rv = SOC_E_TIMEOUT; 2544 break; 2545 } 2546 } 2547 } else 2548 #endif 2549 { 2550 while ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & 2551 SC_MIIM_OP_DONE_TST) == 0) { 2552 if (soc_timeout_check(&to)) { 2553 rv = SOC_E_TIMEOUT; 2554 break; 2555 } 2556 } 2557 } 2558 2559 if (rv == SOC_E_NONE) { 2560 LOG_DEBUG(BSL_LS_SOC_MIIM, 2561 (BSL_META_U(unit, 2562 " Done in %d polls\n"), to.polls)); 2563 } 2564 #ifdef BCM_CMICM_SUPPORT 2565 if(soc_feature(unit, soc_feature_cmicm)) { 2566 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 0); 2567 } else 2568 #endif 2569 { 2570 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_OP_DONE_CLR); 2571 } 2572 } 2573 2574 if (rv == SOC_E_TIMEOUT) { 2575 LOG_ERROR(BSL_LS_SOC_COMMON, 2576 (BSL_META_U(unit, 2577 "MiimTimeOut:__soc_miimc45_write, " 2578 "timeout (id=0x%02x addr=0x%02x data=0x%04x)\n"), 2579 phy_id, phy_reg_addr, phy_wr_data)); 2580 SOC_CONTROL(unit)->stat.err_mii_tmo++; 2581 } 2582 2583 /* Release linkscan pause and MIIM lock */ 2584 MIIM_UNLOCK(unit); 2585 2586 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 2587 soc_linkscan_continue(unit); 2588 } 2589 } 2590 #endif 2591 #endif 2592 return rv; 2593 2594 } 2595 2596 /* 2597 * Function: 2598 * soc_miimc45_write 2599 * Purpose: 2600 * Write a value to a MIIM register. 2601 * Parameters: 2602 * unit - StrataSwitch Unit #. 2603 * phy_id - Phy ID to write (MIIM address) 2604 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 2605 * phy_reg_addr - PHY register to write 2606 * phy_wr_data - Data to write. 2607 * Returns: 2608 * SOC_E_XXX 2609 * Notes: 2610 * Temporarily disables auto link scan if it was enabled. The MIIM 2611 * registers are locked during the operation to prevent multiple 2612 * tasks from trying to access PHY registers simultaneously. This 2613 * is a wrapper around __soc_miimc45_write that should be used for 2614 * oridinary clause 45 writes that are disabled during warmboot. 2615 */ 2616 2617 int 2618 soc_miimc45_write(int unit, uint16 phy_id, uint8 phy_devad, 2619 uint16 phy_reg_addr, uint16 phy_wr_data) 2620 { 2621 2622 return __soc_miimc45_write(unit, phy_id, phy_devad, 2623 phy_reg_addr, phy_wr_data, 0); 2624 } 2625 2626 /* 2627 * Function: 2628 * soc_esw_miimc45_wb_write 2629 * Purpose: 2630 * Write a value from an MII register. 2631 * Parameters: 2632 * unit - StrataSwitch Unit #. 2633 * phy_id - Phy ID to write (MIIM address) 2634 * phy_reg_addr - PHY register to write (Encoded with PMA/PMD, PCS, PHY XS) 2635 * phy_wr_data - 16bit data to write into 2636 * Returns: 2637 * SOC_E_XXX 2638 * Notes: 2639 * This is a wrapper around __soc_miimc45_write that should be used for 2640 * clause 45 writes that should succeed during warmboot. 2641 */ 2642 int 2643 soc_esw_miimc45_wb_write(int unit, uint32 phy_id, 2644 uint32 phy_reg_addr, uint16 phy_wr_data) 2645 { 2646 uint8 dev_addr; 2647 uint16 reg_addr; 2648 2649 dev_addr = SOC_PHY_CLAUSE45_DEVAD(phy_reg_addr); 2650 reg_addr = SOC_PHY_CLAUSE45_REGAD(phy_reg_addr); 2651 2652 return __soc_miimc45_write(unit, (uint16)phy_id, dev_addr, 2653 reg_addr, phy_wr_data, MIIM_WB_C45); 2654 } 2655 2656 /* 2657 * Function: 2658 * soc_miimc45_read 2659 * Purpose: 2660 * Read a value from an MII register. 2661 * Parameters: 2662 * unit - StrataSwitch Unit #. 2663 * phy_id - Phy ID to write (MIIM address) 2664 * phy_devad - Device type (PMA/PMD, PCS, PHY XS) 2665 * phy_reg_addr - PHY register to write 2666 * phy_rd_data - 16bit data to write into 2667 * Returns: 2668 * SOC_E_XXX 2669 * Notes: 2670 * Temporarily disables auto link scan if it was enabled. The MIIM 2671 * registers are locked during the operation to prevent multiple 2672 * tasks from trying to access PHY registers simultaneously. 2673 */ 2674 2675 int 2676 soc_miimc45_read(int unit, uint16 phy_id, uint8 phy_devad, 2677 uint16 phy_reg_addr, uint16 *phy_rd_data) 2678 { 2679 int rv = SOC_E_NONE; 2680 assert(!sal_int_context()); 2681 assert(phy_rd_data); 2682 2683 LOG_VERBOSE(BSL_LS_SOC_MIIM, 2684 (BSL_META_U(unit, 2685 "soc_miimc45_read: id=0x%02x " 2686 "phy_devad=0x%02x addr=0x%02x\n"), 2687 phy_id, phy_devad, phy_reg_addr)); 2688 2689 if (!soc_feature(unit, soc_feature_phy_cl45)) { 2690 return SOC_E_UNAVAIL; 2691 } 2692 #ifdef BCM_ESW_SUPPORT 2693 2694 #if defined(BCM_XGS3_SWITCH_SUPPORT) 2695 { 2696 uint32 phy_param; 2697 uint32 phy_miim_addr; 2698 uint32 cycle_type; 2699 int miim_intr_retry_cnt = MIIM_INTR_RETRY_COUNT; 2700 #ifdef BCM_CMICM_SUPPORT 2701 int cmc = SOC_PCI_CMC(unit); 2702 #endif 2703 #ifdef BCM_CMICX_SUPPORT 2704 if (soc_feature(unit, soc_feature_cmicx)) { 2705 return soc_cmicx_miim_operation(unit, FALSE, SOC_CLAUSE_45, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, MIIM_INTERNAL_EXTERNAL_DELAY_INVALID, phy_id, 2706 ((phy_devad << 16) | (phy_reg_addr & 0xFFFF)), phy_rd_data); 2707 } 2708 #endif /* BCM_CMICX_SUPPORT */ 2709 2710 /* Pause link scanning - and hold MIIM lock */ 2711 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 2712 soc_linkscan_pause(unit); 2713 } 2714 MIIM_LOCK(unit); 2715 2716 /* Write parameter registers and tell CMIC to start */ 2717 phy_param = 0; 2718 if (phy_devad & MIIM_CYCLE_C45_RD) { 2719 cycle_type = MIIM_CYCLE_C45_REG_RD; 2720 } else if (phy_devad & MIIM_CYCLE_C45_RD_ADINC) { 2721 cycle_type = MIIM_CYCLE_C45_REG_RD_ADINC; 2722 } else { 2723 cycle_type = MIIM_CYCLE_AUTO; 2724 } 2725 phy_devad &= ~MIIM_CYCLE_C45_MASK; 2726 #ifdef BCM_CMICM_SUPPORT 2727 if(soc_feature(unit, soc_feature_cmicm)) { 2728 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, &phy_param, 2729 MIIM_CYCLEf, cycle_type); 2730 } else 2731 #endif 2732 { 2733 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2734 MIIM_CYCLEf, cycle_type); 2735 } 2736 if (phy_id & 0x80) { 2737 phy_id &= (~0x80); 2738 #ifdef BCM_CMICM_SUPPORT 2739 if(soc_feature(unit, soc_feature_cmicm)) { 2740 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, 2741 &phy_param, INTERNAL_SELf, 1); 2742 } else 2743 #endif 2744 { 2745 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, 2746 &phy_param, INTERNAL_SELf, 1); 2747 } 2748 } 2749 #if defined(BCM_XGS3_SWITCH_SUPPORT) 2750 if (soc_feature(unit, soc_feature_mdio_enhanced)) { 2751 #ifdef BCM_CMICM_SUPPORT 2752 if(soc_feature(unit, soc_feature_cmicm)) { 2753 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, 2754 &phy_param, C45_SELf, 1); 2755 } else 2756 #endif 2757 { 2758 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, 2759 &phy_param, C45_SELf, 1); 2760 } 2761 #if defined(BCM_TRIDENT_SUPPORT) || defined(BCM_CMICM_SUPPORT) 2762 if (SOC_IS_TD_TT(unit) || soc_feature(unit, soc_feature_cmicm)) { 2763 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 2764 #ifdef BCM_CMICM_SUPPORT 2765 if(soc_feature(unit, soc_feature_cmicm)) { 2766 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, &phy_param, 2767 BUS_IDf, bus_sel); 2768 } else 2769 #endif 2770 { 2771 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2772 BUS_IDf, bus_sel); 2773 } 2774 phy_id &= ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 2775 } else 2776 #endif 2777 #if defined(BCM_SHADOW_SUPPORT) 2778 if (SOC_IS_SHADOW(unit)) { 2779 uint32 bus_sel = PHY_ID_BUS_NUM(phy_id); 2780 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2781 BUS_IDf, bus_sel); 2782 phy_id &= ~(PHY_ID_BUS_UPPER_MASK | PHY_ID_BUS_LOWER_MASK); 2783 } else 2784 #endif 2785 #if defined(BCM_TRX_SUPPORT) 2786 if (SOC_IS_TRX(unit)) { 2787 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2788 BUS0_1_SELf, ((phy_id & 0x20) ? 1 : 0)); 2789 phy_id &= (~0x20); 2790 2791 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, 2792 BUS2_SELf, ((phy_id & 0x40) ? 1 : 0)); 2793 phy_id &= (~0x40); 2794 } else 2795 #endif 2796 { 2797 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, HG_SELf, 2798 ((phy_id & 0x40) ? 1 : 0)); 2799 phy_id &= (~0x40); 2800 } 2801 } 2802 #endif 2803 #ifdef BCM_CMICM_SUPPORT 2804 if(soc_feature(unit, soc_feature_cmicm)) { 2805 soc_reg_field_set(unit, CMIC_CMC0_MIIM_PARAMr, &phy_param, PHY_IDf, phy_id); 2806 phy_miim_addr = 0; 2807 soc_reg_field_set(unit, CMIC_CMC0_MIIM_ADDRESSr, &phy_miim_addr, 2808 CLAUSE_45_DTYPEf, phy_devad); 2809 soc_reg_field_set(unit, CMIC_CMC0_MIIM_ADDRESSr, &phy_miim_addr, 2810 CLAUSE_45_REGADRf, phy_reg_addr); 2811 } else 2812 #endif 2813 { 2814 soc_reg_field_set(unit, CMIC_MIIM_PARAMr, &phy_param, PHY_IDf, phy_id); 2815 phy_miim_addr = 0; 2816 soc_reg_field_set(unit, CMIC_MIIM_ADDRESSr, &phy_miim_addr, 2817 CLAUSE_45_DTYPEf, phy_devad); 2818 soc_reg_field_set(unit, CMIC_MIIM_ADDRESSr, &phy_miim_addr, 2819 CLAUSE_45_REGADRf, phy_reg_addr); 2820 } 2821 2822 #ifdef BCM_CMICM_SUPPORT 2823 if(soc_feature(unit, soc_feature_cmicm)) { 2824 soc_pci_write(unit, CMIC_CMCx_MIIM_ADDRESS_OFFSET(cmc), phy_miim_addr); 2825 soc_pci_write(unit, CMIC_CMCx_MIIM_PARAM_OFFSET(cmc), phy_param); 2826 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 2); 2827 } else 2828 #endif 2829 { 2830 WRITE_CMIC_MIIM_ADDRESSr(unit, phy_miim_addr); 2831 soc_pci_write(unit, CMIC_MIIM_PARAM, phy_param); 2832 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_RD_START_SET); 2833 } 2834 2835 /* Wait for completion using either the interrupt or polling method */ 2836 2837 if (SOC_CONTROL(unit)->miimIntrEnb) { 2838 #ifdef BCM_CMICM_SUPPORT 2839 if(soc_feature(unit, soc_feature_cmicm)) { 2840 soc_cmicm_intr0_enable(unit, IRQ_CMCx_MIIM_OP_DONE); 2841 } else 2842 #endif 2843 { 2844 soc_intr_enable(unit, IRQ_MIIM_OP_DONE); 2845 } 2846 2847 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2848 SOC_CONTROL(unit)->miimTimeout) != 0) { 2849 #ifdef BCM_CMICM_SUPPORT 2850 if(soc_feature(unit, soc_feature_cmicm)) { 2851 if ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 2852 CMIC_MIIM_OPN_DONE) == 0) { 2853 /* MIIM HW operation not complete */ 2854 rv = SOC_E_TIMEOUT; 2855 } else { 2856 /* MIIM HW operation complete but no intr received yet 2857 * Retry for MIIM Intr for busy system 2858 * before declaring timeout */ 2859 rv = SOC_E_TIMEOUT; 2860 while (miim_intr_retry_cnt) { 2861 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2862 MIIM_INTR_RETRY_TIMEOUT) == 0) { 2863 rv = SOC_E_NONE; 2864 break; 2865 } 2866 miim_intr_retry_cnt--; 2867 } 2868 } 2869 } else 2870 #endif 2871 { 2872 if ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & SC_MIIM_OP_DONE_TST) == 0) { 2873 /* MIIM HW operation not complete */ 2874 rv = SOC_E_TIMEOUT; 2875 } else { 2876 /* MIIM HW operation complete but no intr received yet 2877 * Retry for MIIM Intr for busy system 2878 * before declaring timeout */ 2879 rv = SOC_E_TIMEOUT; 2880 while (miim_intr_retry_cnt) { 2881 if (sal_sem_take(SOC_CONTROL(unit)->miimIntr, 2882 MIIM_INTR_RETRY_TIMEOUT) == 0) { 2883 rv = SOC_E_NONE; 2884 break; 2885 } 2886 miim_intr_retry_cnt--; 2887 } 2888 } 2889 } 2890 } else { 2891 LOG_DEBUG(BSL_LS_SOC_MIIM, 2892 (BSL_META_U(unit, 2893 " Interrupt received\n"))); 2894 } 2895 2896 #ifdef BCM_CMICM_SUPPORT 2897 if(soc_feature(unit, soc_feature_cmicm)) { 2898 soc_cmicm_intr0_disable(unit, IRQ_CMCx_MIIM_OP_DONE); 2899 } else 2900 #endif 2901 { 2902 soc_intr_disable(unit, IRQ_MIIM_OP_DONE); 2903 } 2904 } else { 2905 soc_timeout_t to; 2906 2907 soc_timeout_init(&to, SOC_CONTROL(unit)->miimTimeout, MIIM_POLL_TIMEOUT); 2908 2909 #ifdef BCM_CMICM_SUPPORT 2910 if(soc_feature(unit, soc_feature_cmicm)) { 2911 while ((soc_pci_read(unit, CMIC_CMCx_MIIM_STAT_OFFSET(cmc)) & 2912 CMIC_MIIM_OPN_DONE) == 0) { 2913 if (soc_timeout_check(&to)) { 2914 rv = SOC_E_TIMEOUT; 2915 break; 2916 } 2917 } 2918 } else 2919 #endif 2920 { 2921 while ((soc_pci_read(unit, CMIC_SCHAN_CTRL) & 2922 SC_MIIM_OP_DONE_TST) == 0) { 2923 if (soc_timeout_check(&to)) { 2924 rv = SOC_E_TIMEOUT; 2925 break; 2926 } 2927 } 2928 } 2929 2930 if (rv == SOC_E_NONE) { 2931 LOG_DEBUG(BSL_LS_SOC_MIIM, 2932 (BSL_META_U(unit, 2933 " Done in %d polls\n"), to.polls)); 2934 } 2935 #ifdef BCM_CMICM_SUPPORT 2936 if(soc_feature(unit, soc_feature_cmicm)) { 2937 soc_pci_write(unit, CMIC_CMCx_MIIM_CTRL_OFFSET(cmc), 0); 2938 } else 2939 #endif 2940 { 2941 soc_pci_write(unit, CMIC_SCHAN_CTRL, SC_MIIM_OP_DONE_CLR); 2942 } 2943 } 2944 2945 if (rv == SOC_E_TIMEOUT) { 2946 LOG_ERROR(BSL_LS_SOC_COMMON, 2947 (BSL_META_U(unit, 2948 "MiimTimeOut:soc_miimc45_read, " 2949 "timeout (id=0x%02x addr=0x%02x)\n"), 2950 phy_id, phy_reg_addr)); 2951 SOC_CONTROL(unit)->stat.err_mii_tmo++; 2952 } else { 2953 #ifdef BCM_CMICM_SUPPORT 2954 if(soc_feature(unit, soc_feature_cmicm)) { 2955 *phy_rd_data = (uint16)soc_pci_read(unit, CMIC_CMCx_MIIM_READ_DATA_OFFSET(cmc)); 2956 } else 2957 #endif 2958 { 2959 *phy_rd_data = (uint16)soc_pci_read(unit, CMIC_MIIM_READ_DATA); 2960 } 2961 2962 LOG_VERBOSE(BSL_LS_SOC_MIIM, 2963 (BSL_META_U(unit, 2964 "soc_miimc45_read: read data=0x%04x\n"), *phy_rd_data)); 2965 } 2966 2967 /* Release linkscan pause and MIIM lock */ 2968 MIIM_UNLOCK(unit); 2969 2970 if (!soc_feature(unit, soc_feature_linkscan_continuous)) { 2971 soc_linkscan_continue(unit); 2972 } 2973 } 2974 #endif 2975 #endif 2976 return rv; 2977 2978 } 2979 2980 /* 2981 * Function: 2982 * soc_sbus_mdio_write 2983 * Purpose: 2984 * Write to an MII register via CMIC SBUS (S-channel) interface. 2985 * Parameters: 2986 * unit - StrataSwitch Unit #. 2987 * phy_id - Phy ID to write (MIIM address) 2988 * phy_reg_addr - PHY register to write 2989 * phy_wr_data - 32-bit data to write 2990 * Returns: 2991 * SOC_E_XXX 2992 * Notes: 2993 * This function is simply a wrapper for a device-specific implmentation. 2994 */ 2995 2996 int 2997 soc_sbus_mdio_write(int unit, uint16 phy_id, 2998 uint32 phy_reg_addr, uint32 phy_wr_data) 2999 { 3000 soc_sbus_mdio_write_f sbus_write; 3001 3002 sbus_write = SOC_FUNCTIONS(unit)->soc_sbus_mdio_write; 3003 if (sbus_write != NULL) { 3004 return sbus_write(unit, phy_id, phy_reg_addr, phy_wr_data); 3005 } 3006 return SOC_E_UNAVAIL; 3007 } 3008 3009 /* 3010 * Function: 3011 * soc_sbus_mdio_read 3012 * Purpose: 3013 * Read from an MII register via CMIC SBUS (S-channel) interface. 3014 * Parameters: 3015 * unit - StrataSwitch Unit #. 3016 * phy_id - Phy ID to write (MIIM address) 3017 * phy_reg_addr - PHY register to write 3018 * phy_rd_data - 32-bit data to read into 3019 * Returns: 3020 * SOC_E_XXX 3021 * Notes: 3022 * This function is simply a wrapper for a device-specific implmentation. 3023 */ 3024 3025 int 3026 soc_sbus_mdio_read(int unit, uint16 phy_id, 3027 uint32 phy_reg_addr, uint32 *phy_rd_data) 3028 { 3029 soc_sbus_mdio_read_f sbus_read; 3030 3031 sbus_read = SOC_FUNCTIONS(unit)->soc_sbus_mdio_read; 3032 if (sbus_read != NULL) { 3033 return sbus_read(unit, phy_id, phy_reg_addr, phy_rd_data); 3034 } 3035 return SOC_E_UNAVAIL; 3036 } 3037 3038 #ifdef PORTMOD_SUPPORT 3039 /** 3040 * @brief generic function for register write for PM4X25, 3041 * PM4X10, PM 12X10 3042 * @param user_acc - user data. this function expect to get 3043 * portmod_phy_op_data_t structure 3044 * @param core_address - only 5 bits of PHY id used in case 3045 * of sbus 3046 * @param reg_addr - the reigister addrress 3047 * @param val - the value to write to register. 16 bits value + 3048 * 16 bits mask 3049 3050 */ 3051 int 3052 portmod_ext_phy_mdio_c45_reg_read( void* user_acc, uint32_t core_addr, uint32 reg_addr, uint32 *val) 3053 { 3054 int rv= SOC_E_NONE; 3055 portmod_default_user_access_t *user_data = user_acc; 3056 uint32 phy_id; 3057 uint16 rd_data; 3058 3059 phy_id = core_addr; 3060 3061 if(user_data == NULL){ 3062 return SOC_E_PARAM; 3063 } 3064 3065 if (SOC_IS_SAND(user_data->unit)) { 3066 rv = soc_dcmn_miim_cl45_read(user_data->unit, phy_id, reg_addr, &rd_data); 3067 } else { 3068 rv = soc_esw_miimc45_read(user_data->unit, phy_id, reg_addr, &rd_data); 3069 } 3070 3071 *val = rd_data; 3072 return rv; 3073 3074 } 3075 3076 3077 /** 3078 * @brief generic function for register write for PM4X25, 3079 * PM4X10, PM 12X10 3080 * @param user_acc - user data. this function expect to get 3081 * portmod_phy_op_data_t structure 3082 * @param core_address - only 5 bits of PHY id used in case 3083 * of sbus 3084 * @param reg_addr - the reigister addrress 3085 * @param val - the value to write to register. 16 bits value + 3086 * 16 bits mask 3087 3088 */ 3089 int 3090 portmod_ext_phy_mdio_c45_reg_write( void* user_acc, uint32 core_addr, uint32 reg_addr, uint32 val) 3091 { 3092 int rv= SOC_E_NONE; 3093 portmod_default_user_access_t *user_data = user_acc; 3094 uint32 phy_id; 3095 uint16 wr_data; 3096 3097 if(user_data == NULL){ 3098 return SOC_E_PARAM; 3099 } 3100 3101 3102 phy_id = core_addr; 3103 wr_data = val; 3104 3105 if (SOC_IS_SAND(user_data->unit)) { 3106 rv = soc_dcmn_miim_cl45_write(user_data->unit, phy_id, reg_addr, wr_data); 3107 } else { 3108 if(SOC_WARM_BOOT(user_data->unit)) { 3109 rv = soc_esw_miimc45_wb_write(user_data->unit, phy_id, reg_addr, wr_data); 3110 } else { 3111 rv = soc_esw_miimc45_write(user_data->unit, phy_id, reg_addr, wr_data); 3112 } 3113 } 3114 return rv; 3115 } 3116 3117 #endif /* PORTMOD_SUPPORT */