1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "nge.h" 28 29 #undef NGE_DBG 30 #define NGE_DBG NGE_DBG_MII /* debug flag for this code */ 31 32 /* 33 * The arrays below can be indexed by the MODE bits from the mac2phy 34 * register to determine the current speed/duplex settings. 35 */ 36 static const int16_t nge_copper_link_speed[] = { 37 0, /* MII_AUX_STATUS_MODE_NONE */ 38 10, /* MII_AUX_STAT0,US_MODE_10 */ 39 100, /* MII_AUX_STAT0,US_MODE_100 */ 40 1000, /* MII_AUX_STAT0,US_MODE_1000 */ 41 }; 42 43 static const int8_t nge_copper_link_duplex[] = { 44 LINK_DUPLEX_UNKNOWN, /* MII_DUPLEX_NONE */ 45 LINK_DUPLEX_HALF, /* MII_DUPLEX_HALF */ 46 LINK_DUPLEX_FULL, /* MII_DUPLEX_FULL */ 47 }; 48 49 50 static uint16_t nge_mii_access(nge_t *ngep, nge_regno_t regno, 51 uint16_t data, uint32_t cmd); 52 #pragma inline(nge_mii_access) 53 54 static uint16_t 55 nge_mii_access(nge_t *ngep, nge_regno_t regno, uint16_t data, uint32_t cmd) 56 { 57 uint16_t tries; 58 uint16_t mdio_data; 59 nge_mdio_adr mdio_adr; 60 nge_mintr_src intr_src; 61 62 NGE_TRACE(("nge_mii_access($%p, 0x%lx, 0x%x, 0x%x)", 63 (void *)ngep, regno, data, cmd)); 64 65 /* 66 * Clear the privous interrupt event 67 */ 68 intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC); 69 nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val); 70 71 /* 72 * Check whether the current operation has been finished 73 */ 74 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR); 75 for (tries = 0; tries < 30; tries ++) { 76 if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR) 77 break; 78 drv_usecwait(10); 79 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR); 80 } 81 82 /* 83 * The current operation can not be finished successfully 84 * The driver should halt the current operation 85 */ 86 if (tries == 30) { 87 mdio_adr.adr_bits.mdio_clc = NGE_SET; 88 nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val); 89 drv_usecwait(100); 90 } 91 92 /* 93 * Assemble the operation cmd 94 */ 95 mdio_adr.adr_bits.phy_reg = (uint16_t)regno; 96 mdio_adr.adr_bits.phy_adr = ngep->phy_xmii_addr; 97 mdio_adr.adr_bits.mdio_rw = (cmd == NGE_MDIO_WRITE) ? 1 : 0; 98 99 100 if (cmd == NGE_MDIO_WRITE) 101 nge_reg_put16(ngep, NGE_MDIO_DATA, data); 102 103 nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val); 104 105 /* 106 * To check whether the read/write operation is finished 107 */ 108 for (tries = 0; tries < 300; tries ++) { 109 drv_usecwait(10); 110 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR); 111 if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR) 112 break; 113 } 114 if (tries == 300) 115 return ((uint16_t)~0); 116 117 /* 118 * Read the data from MDIO data register 119 */ 120 if (cmd == NGE_MDIO_READ) 121 mdio_data = nge_reg_get16(ngep, NGE_MDIO_DATA); 122 123 /* 124 * To check whether the read/write operation is valid 125 */ 126 intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC); 127 nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val); 128 if (intr_src.src_bits.mrei == NGE_SET) 129 return ((uint16_t)~0); 130 131 return (mdio_data); 132 } 133 134 uint16_t nge_mii_get16(nge_t *ngep, nge_regno_t regno); 135 #pragma inline(nge_mii_get16) 136 137 uint16_t 138 nge_mii_get16(nge_t *ngep, nge_regno_t regno) 139 { 140 141 return (nge_mii_access(ngep, regno, 0, NGE_MDIO_READ)); 142 } 143 144 void nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data); 145 #pragma inline(nge_mii_put16) 146 147 void 148 nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data) 149 { 150 151 (void) nge_mii_access(ngep, regno, data, NGE_MDIO_WRITE); 152 } 153 154 /* 155 * Basic low-level function to probe for a PHY 156 * 157 * Returns TRUE if the PHY responds with valid data, FALSE otherwise 158 */ 159 static boolean_t 160 nge_phy_probe(nge_t *ngep) 161 { 162 int i; 163 uint16_t phy_status; 164 uint16_t phyidh; 165 uint16_t phyidl; 166 167 NGE_TRACE(("nge_phy_probe($%p)", (void *)ngep)); 168 169 /* 170 * Scan the phys to find the right address 171 * of the phy 172 * 173 * Probe maximum for 32 phy addresses 174 */ 175 for (i = 0; i < NGE_PHY_NUMBER; i++) { 176 ngep->phy_xmii_addr = i; 177 /* 178 * Read the MII_STATUS register twice, in 179 * order to clear any sticky bits (but they should 180 * have been cleared by the RESET, I think). 181 */ 182 phy_status = nge_mii_get16(ngep, MII_STATUS); 183 phy_status = nge_mii_get16(ngep, MII_STATUS); 184 if (phy_status != 0xffff) { 185 phyidh = nge_mii_get16(ngep, MII_PHYIDH); 186 phyidl = nge_mii_get16(ngep, MII_PHYIDL); 187 ngep->phy_id = 188 (((uint32_t)phyidh << 16) |(phyidl & MII_IDL_MASK)); 189 NGE_DEBUG(("nge_phy_probe: status 0x%x, phy id 0x%x", 190 phy_status, ngep->phy_id)); 191 192 return (B_TRUE); 193 } 194 } 195 196 return (B_FALSE); 197 } 198 199 200 /* 201 * Basic low-level function to powerup the phy and remove the isolation 202 */ 203 204 static boolean_t 205 nge_phy_recover(nge_t *ngep) 206 { 207 uint16_t control; 208 uint16_t count; 209 210 NGE_TRACE(("nge_phy_recover($%p)", (void *)ngep)); 211 control = nge_mii_get16(ngep, MII_CONTROL); 212 control &= ~(MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE); 213 nge_mii_put16(ngep, MII_CONTROL, control); 214 for (count = 0; ++count < 10; ) { 215 drv_usecwait(5); 216 control = nge_mii_get16(ngep, MII_CONTROL); 217 if (BIC(control, MII_CONTROL_PWRDN)) 218 return (B_TRUE); 219 } 220 221 return (B_FALSE); 222 } 223 /* 224 * Basic low-level function to reset the PHY. 225 * Doesn't incorporate any special-case workarounds. 226 * 227 * Returns TRUE on success, FALSE if the RESET bit doesn't clear 228 */ 229 boolean_t 230 nge_phy_reset(nge_t *ngep) 231 { 232 uint16_t control; 233 uint_t count; 234 235 NGE_TRACE(("nge_phy_reset($%p)", (void *)ngep)); 236 237 ASSERT(mutex_owned(ngep->genlock)); 238 239 /* 240 * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear 241 */ 242 control = nge_mii_get16(ngep, MII_CONTROL); 243 control |= MII_CONTROL_RESET; 244 nge_mii_put16(ngep, MII_CONTROL, control); 245 /* We should wait for 500ms. It's defined in the manual */ 246 delay(drv_usectohz(500000)); 247 for (count = 0; ++count < 10; ) { 248 drv_usecwait(5); 249 control = nge_mii_get16(ngep, MII_CONTROL); 250 if (BIC(control, MII_CONTROL_RESET)) 251 return (B_TRUE); 252 } 253 NGE_DEBUG(("nge_phy_reset: FAILED, control now 0x%x", control)); 254 255 return (B_FALSE); 256 } 257 258 static boolean_t 259 nge_phy_restart(nge_t *ngep) 260 { 261 uint16_t mii_reg; 262 263 if (!nge_phy_recover(ngep)) 264 return (B_FALSE); 265 if (!nge_phy_reset(ngep)) 266 return (B_FALSE); 267 268 if (MII_PHY_MFG(ngep->phy_id) == MII_ID_CICADA) { 269 if (ngep->phy_mode == RGMII_IN) { 270 mii_reg = nge_mii_get16(ngep, 271 MII_CICADA_EXT_CONTROL); 272 mii_reg &= ~(MII_CICADA_MODE_SELECT_BITS 273 | MII_CICADA_POWER_SUPPLY_BITS); 274 mii_reg |= (MII_CICADA_MODE_SELECT_RGMII 275 | MII_CICADA_POWER_SUPPLY_2_5V); 276 nge_mii_put16(ngep, MII_CICADA_EXT_CONTROL, mii_reg); 277 278 mii_reg = nge_mii_get16(ngep, 279 MII_CICADA_AUXCTRL_STATUS); 280 mii_reg |= MII_CICADA_PIN_PRORITY_SETTING; 281 nge_mii_put16(ngep, MII_CICADA_AUXCTRL_STATUS, 282 mii_reg); 283 } else { 284 mii_reg = nge_mii_get16(ngep, 285 MII_CICADA_10BASET_CONTROL); 286 mii_reg |= MII_CICADA_DISABLE_ECHO_MODE; 287 nge_mii_put16(ngep, 288 MII_CICADA_10BASET_CONTROL, mii_reg); 289 290 mii_reg = nge_mii_get16(ngep, 291 MII_CICADA_BYPASS_CONTROL); 292 mii_reg &= (~CICADA_125MHZ_CLOCK_ENABLE); 293 nge_mii_put16(ngep, MII_CICADA_BYPASS_CONTROL, mii_reg); 294 } 295 } 296 297 return (B_TRUE); 298 } 299 300 /* 301 * Synchronise the (copper) PHY's speed/duplex/autonegotiation capabilities 302 * and advertisements with the required settings as specified by the various 303 * param_* variables that can be poked via the NDD interface. 304 * 305 * We always reset the PHY and reprogram *all* the relevant registers, 306 * not just those changed. This should cause the link to go down, and then 307 * back up again once the link is stable and autonegotiation (if enabled) 308 * is complete. We should get a link state change interrupt somewhere along 309 * the way ... 310 * 311 * NOTE: <genlock> must already be held by the caller 312 */ 313 static void 314 nge_update_copper(nge_t *ngep) 315 { 316 uint16_t control; 317 uint16_t gigctrl; 318 uint16_t anar; 319 boolean_t adv_autoneg; 320 boolean_t adv_pause; 321 boolean_t adv_asym_pause; 322 boolean_t adv_1000fdx; 323 boolean_t adv_100fdx; 324 boolean_t adv_100hdx; 325 boolean_t adv_10fdx; 326 boolean_t adv_10hdx; 327 328 NGE_TRACE(("nge_update_copper($%p)", (void *)ngep)); 329 330 ASSERT(mutex_owned(ngep->genlock)); 331 332 NGE_DEBUG(("nge_update_copper: autoneg %d " 333 "pause %d asym_pause %d " 334 "1000fdx %d " 335 "100fdx %d 100hdx %d " 336 "10fdx %d 10hdx %d ", 337 ngep->param_adv_autoneg, 338 ngep->param_adv_pause, ngep->param_adv_asym_pause, 339 ngep->param_adv_1000fdx, 340 ngep->param_adv_100fdx, ngep->param_adv_100hdx, 341 ngep->param_adv_10fdx, ngep->param_adv_10hdx)); 342 343 control = anar = gigctrl = 0; 344 345 /* 346 * PHY settings are normally based on the param_* variables, 347 * but if any loopback mode is in effect, that takes precedence. 348 * 349 * NGE supports MAC-internal loopback, PHY-internal loopback, 350 * and External loopback at a variety of speeds (with a special 351 * cable). In all cases, autoneg is turned OFF, full-duplex 352 * is turned ON, and the speed/mastership is forced. 353 */ 354 switch (ngep->param_loop_mode) { 355 case NGE_LOOP_NONE: 356 default: 357 adv_pause = ngep->param_adv_pause; 358 adv_autoneg = ngep->param_adv_autoneg; 359 adv_asym_pause = ngep->param_adv_asym_pause; 360 if (ngep->phy_mode == MII_IN) { 361 adv_1000fdx = ngep->param_adv_1000fdx = B_FALSE; 362 } 363 adv_1000fdx = ngep->param_adv_1000fdx; 364 adv_100fdx = ngep->param_adv_100fdx; 365 adv_100hdx = ngep->param_adv_100hdx; 366 adv_10fdx = ngep->param_adv_10fdx; 367 adv_10hdx = ngep->param_adv_10hdx; 368 369 break; 370 371 case NGE_LOOP_EXTERNAL_100: 372 case NGE_LOOP_EXTERNAL_10: 373 case NGE_LOOP_INTERNAL_PHY: 374 adv_autoneg = adv_pause = adv_asym_pause = B_FALSE; 375 adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE; 376 adv_100hdx = adv_10hdx = B_FALSE; 377 ngep->param_link_duplex = LINK_DUPLEX_FULL; 378 379 switch (ngep->param_loop_mode) { 380 case NGE_LOOP_EXTERNAL_100: 381 ngep->param_link_speed = 100; 382 adv_100fdx = B_TRUE; 383 break; 384 385 case NGE_LOOP_EXTERNAL_10: 386 ngep->param_link_speed = 10; 387 adv_10fdx = B_TRUE; 388 break; 389 390 case NGE_LOOP_INTERNAL_PHY: 391 ngep->param_link_speed = 1000; 392 adv_1000fdx = B_TRUE; 393 break; 394 395 } 396 } 397 NGE_DEBUG(("nge_update_copper: autoneg %d " 398 "pause %d asym_pause %d " 399 "1000fdx %d " 400 "100fdx %d 100hdx %d " 401 "10fdx %d 10hdx %d ", 402 adv_autoneg, 403 adv_pause, adv_asym_pause, 404 adv_1000fdx, 405 adv_100fdx, adv_100hdx, 406 adv_10fdx, adv_10hdx)); 407 408 /* 409 * We should have at least one technology capability set; 410 * if not, we select a default of 10Mb/s half-duplex 411 */ 412 if (!adv_1000fdx && !adv_100fdx && !adv_10fdx && 413 !adv_100hdx && !adv_10hdx) 414 adv_10hdx = B_TRUE; 415 416 /* 417 * Now transform the adv_* variables into the proper settings 418 * of the PHY registers ... 419 * 420 * If autonegotiation is (now) enabled, we want to trigger 421 * a new autonegotiation cycle once the PHY has been 422 * programmed with the capabilities to be advertised. 423 */ 424 if (adv_autoneg) 425 control |= MII_CONTROL_ANE|MII_CONTROL_RSAN; 426 427 if (adv_1000fdx) 428 control |= MII_CONTROL_1000MB|MII_CONTROL_FDUPLEX; 429 else if (adv_100fdx) 430 control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX; 431 else if (adv_100hdx) 432 control |= MII_CONTROL_100MB; 433 else if (adv_10fdx) 434 control |= MII_CONTROL_FDUPLEX; 435 else if (adv_10hdx) 436 control |= 0; 437 else 438 { _NOTE(EMPTY); } /* Can't get here anyway ... */ 439 440 if (adv_1000fdx) 441 gigctrl |= MII_1000BT_CTL_ADV_FDX; 442 if (adv_100fdx) 443 anar |= MII_ABILITY_100BASE_TX_FD; 444 if (adv_100hdx) 445 anar |= MII_ABILITY_100BASE_TX; 446 if (adv_10fdx) 447 anar |= MII_ABILITY_10BASE_T_FD; 448 if (adv_10hdx) 449 anar |= MII_ABILITY_10BASE_T; 450 451 if (adv_pause) 452 anar |= MII_ABILITY_PAUSE; 453 if (adv_asym_pause) 454 anar |= MII_ABILITY_ASMPAUSE; 455 456 /* 457 * Munge in any other fixed bits we require ... 458 */ 459 anar |= MII_AN_SELECTOR_8023; 460 461 /* 462 * Restart the PHY and write the new values. 463 */ 464 nge_mii_put16(ngep, MII_AN_ADVERT, anar); 465 nge_mii_put16(ngep, MII_CONTROL, control); 466 nge_mii_put16(ngep, MII_1000BASE_T_CONTROL, gigctrl); 467 if (!nge_phy_restart(ngep)) 468 nge_error(ngep, "nge_update_copper: failed to restart phy"); 469 /* 470 * Loopback bit in control register is not reset sticky 471 * write it after PHY restart. 472 */ 473 if (ngep->param_loop_mode == NGE_LOOP_INTERNAL_PHY) { 474 control = nge_mii_get16(ngep, MII_CONTROL); 475 control |= MII_CONTROL_LOOPBACK; 476 nge_mii_put16(ngep, MII_CONTROL, control); 477 } 478 } 479 480 static boolean_t 481 nge_check_copper(nge_t *ngep) 482 { 483 uint16_t mii_status; 484 uint16_t mii_exstatus; 485 uint16_t mii_excontrol; 486 uint16_t anar; 487 uint16_t lpan; 488 uint_t speed; 489 uint_t duplex; 490 boolean_t linkup; 491 nge_mii_cs mii_cs; 492 nge_mintr_src mintr_src; 493 494 speed = UNKOWN_SPEED; 495 duplex = UNKOWN_DUPLEX; 496 /* 497 * Read the status from the PHY (which is self-clearing 498 * on read!); also read & clear the main (Ethernet) MAC status 499 * (the relevant bits of this are write-one-to-clear). 500 */ 501 mii_status = nge_mii_get16(ngep, MII_STATUS); 502 mii_cs.cs_val = nge_reg_get32(ngep, NGE_MII_CS); 503 mintr_src.src_val = nge_reg_get32(ngep, NGE_MINTR_SRC); 504 nge_reg_put32(ngep, NGE_MINTR_SRC, mintr_src.src_val); 505 506 NGE_DEBUG(("nge_check_copper: link %d/%s, MII status 0x%x " 507 "(was 0x%x)", ngep->link_state, 508 UPORDOWN(ngep->param_link_up), mii_status, 509 ngep->phy_gen_status)); 510 511 do { 512 /* 513 * If the PHY status changed, record the time 514 */ 515 switch (ngep->phy_mode) { 516 default: 517 case RGMII_IN: 518 519 /* 520 * Judge the giga speed by reading control 521 * and status register 522 */ 523 mii_excontrol = nge_mii_get16(ngep, 524 MII_1000BASE_T_CONTROL); 525 mii_exstatus = nge_mii_get16(ngep, 526 MII_1000BASE_T_STATUS); 527 if ((mii_excontrol & MII_1000BT_CTL_ADV_FDX) && 528 (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP)) { 529 speed = NGE_1000M; 530 duplex = NGE_FD; 531 } else { 532 anar = nge_mii_get16(ngep, MII_AN_ADVERT); 533 lpan = nge_mii_get16(ngep, MII_AN_LPABLE); 534 if (lpan != 0) 535 anar = (anar & lpan); 536 if (anar & MII_100BASET_FD) { 537 speed = NGE_100M; 538 duplex = NGE_FD; 539 } else if (anar & MII_100BASET_HD) { 540 speed = NGE_100M; 541 duplex = NGE_HD; 542 } else if (anar & MII_10BASET_FD) { 543 speed = NGE_10M; 544 duplex = NGE_FD; 545 } else if (anar & MII_10BASET_HD) { 546 speed = NGE_10M; 547 duplex = NGE_HD; 548 } 549 } 550 break; 551 case MII_IN: 552 anar = nge_mii_get16(ngep, MII_AN_ADVERT); 553 lpan = nge_mii_get16(ngep, MII_AN_LPABLE); 554 if (lpan != 0) 555 anar = (anar & lpan); 556 557 if (anar & MII_100BASET_FD) { 558 speed = NGE_100M; 559 duplex = NGE_FD; 560 } else if (anar & MII_100BASET_HD) { 561 speed = NGE_100M; 562 duplex = NGE_HD; 563 } else if (anar & MII_10BASET_FD) { 564 speed = NGE_10M; 565 duplex = NGE_FD; 566 } else if (anar & MII_10BASET_HD) { 567 speed = NGE_10M; 568 duplex = NGE_HD; 569 } 570 break; 571 } 572 573 574 /* 575 * We will only consider the link UP if all the readings 576 * are consistent and give meaningful results ... 577 */ 578 linkup = nge_copper_link_speed[speed] > 0; 579 linkup &= nge_copper_link_duplex[duplex] != LINK_DUPLEX_UNKNOWN; 580 linkup &= BIS(mii_status, MII_STATUS_LINKUP); 581 linkup &= BIS(mii_cs.cs_val, MII_STATUS_LINKUP); 582 583 /* 584 * Record current register values, then reread status 585 * register & loop until it stabilises ... 586 */ 587 ngep->phy_gen_status = mii_status; 588 mii_status = nge_mii_get16(ngep, MII_STATUS); 589 } while (mii_status != ngep->phy_gen_status); 590 591 /* Get the Link Partner Ability */ 592 mii_exstatus = nge_mii_get16(ngep, MII_1000BASE_T_STATUS); 593 lpan = nge_mii_get16(ngep, MII_AN_LPABLE); 594 if (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP) { 595 ngep->param_lp_autoneg = B_TRUE; 596 ngep->param_link_autoneg = B_TRUE; 597 ngep->param_lp_1000fdx = B_TRUE; 598 } 599 if (mii_exstatus & MII_1000BT_STAT_LP_HDX_CAP) { 600 ngep->param_lp_autoneg = B_TRUE; 601 ngep->param_link_autoneg = B_TRUE; 602 ngep->param_lp_1000hdx = B_TRUE; 603 } 604 if (lpan & MII_100BASET_FD) 605 ngep->param_lp_100fdx = B_TRUE; 606 if (lpan & MII_100BASET_HD) 607 ngep->param_lp_100hdx = B_TRUE; 608 if (lpan & MII_10BASET_FD) 609 ngep->param_lp_10fdx = B_TRUE; 610 if (lpan & MII_10BASET_HD) 611 ngep->param_lp_10hdx = B_TRUE; 612 if (lpan & MII_LP_ASYM_PAUSE) 613 ngep->param_lp_asym_pause = B_TRUE; 614 if (lpan & MII_LP_PAUSE) 615 ngep->param_lp_pause = B_TRUE; 616 ngep->param_link_tx_pause = B_FALSE; 617 618 if (ngep->param_adv_autoneg) 619 ngep->param_link_rx_pause = B_FALSE; 620 else 621 ngep->param_link_rx_pause = ngep->param_adv_pause; 622 if (linkup) { 623 ngep->param_link_up = linkup; 624 ngep->param_link_speed = nge_copper_link_speed[speed]; 625 ngep->param_link_duplex = nge_copper_link_duplex[duplex]; 626 } else { 627 ngep->param_link_up = B_FALSE; 628 ngep->param_link_speed = 0; 629 ngep->param_link_duplex = LINK_DUPLEX_UNKNOWN; 630 } 631 NGE_DEBUG(("nge_check_copper: link now %s speed %d duplex %d", 632 UPORDOWN(ngep->param_link_up), 633 ngep->param_link_speed, 634 ngep->param_link_duplex)); 635 636 return (B_FALSE); 637 } 638 639 /* 640 * Because the network chipset embedded in Ck8-04 bridge is only a mac chipset, 641 * the different vendor can use different media(serdes and copper). 642 * To make it easier to extend the driver to support more platforms with ck8-04, 643 * For example, one platform with serdes support, 644 * wrapper phy operation functions. 645 * But now, only supply copper phy operations. 646 */ 647 static const phys_ops_t copper_ops = { 648 nge_phy_restart, 649 nge_update_copper, 650 nge_check_copper 651 }; 652 653 /* 654 * Here we have to determine which media we're using (copper or serdes). 655 * Once that's done, we can initialise the physical layer appropriately. 656 */ 657 void 658 nge_phys_init(nge_t *ngep) 659 { 660 nge_mac2phy m2p; 661 NGE_TRACE(("nge_phys_init($%p)", (void *)ngep)); 662 663 /* Get the phy type from MAC2PHY register */ 664 m2p.m2p_val = nge_reg_get32(ngep, NGE_MAC2PHY); 665 ngep->phy_mode = m2p.m2p_bits.in_type; 666 if ((ngep->phy_mode != RGMII_IN) && (ngep->phy_mode != MII_IN)) { 667 ngep->phy_mode = RGMII_IN; 668 m2p.m2p_bits.in_type = RGMII_IN; 669 nge_reg_put32(ngep, NGE_MAC2PHY, m2p.m2p_val); 670 } 671 672 /* 673 * Probe for the type of the PHY. 674 */ 675 ngep->phy_xmii_addr = 1; 676 (void) nge_phy_probe(ngep); 677 ngep->chipinfo.flags |= CHIP_FLAG_COPPER; 678 ngep->physops = &copper_ops; 679 (*(ngep->physops->phys_restart))(ngep); 680 } 681