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