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