static void bcm5411_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 0x1c, 0x8c23 }, { 0x1c, 0x8ca3 }, { 0x1c, 0x8c23 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); }
static void brgphy_fixup_adc_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); }
void bcm54k2_load_dspcode(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { 4, 0x01e1 }, { 9, 0x0300 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); }
static void brgphy_fixup_crc_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_DSP_RW_PORT, 0x0a75 }, { 0x1c, 0x8c68 }, { 0x1c, 0x8d68 }, { 0x1c, 0x8c68 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); }
static int acphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { int reg; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; /* Wake & deisolate up if necessary */ reg = PHY_READ(sc, MII_BMCR); if (reg & (BMCR_ISO | BMCR_PDOWN)) PHY_WRITE(sc, MII_BMCR, reg & ~(BMCR_ISO | BMCR_PDOWN)); mii_phy_setmedia(sc); break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * This PHY's autonegotiation doesn't need to be kicked. */ break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static int axphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; switch (cmd) { case MII_POLLSTAT: if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); break; case MII_MEDIACHG: if (IFM_INST(ife->ifm_media) != sc->mii_inst) { reg = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); return (0); } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; mii_phy_setmedia(sc); break; case MII_TICK: if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; } /* Update the media status. */ axphy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static void brgphy_fixup_adjust_trim(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x110b }, { BRGPHY_MII_TEST1, 0x0014 }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); }
static void ihphyattach(device_t parent, device_t self, void *aux) { struct mii_softc *sc = device_private(self); struct mii_attach_args *ma = aux; struct mii_data *mii = ma->mii_data; const struct mii_phydesc *mpd; int reg; mpd = mii_phy_match(ma, ihphys); aprint_naive(": Media interface\n"); aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2)); sc->mii_dev = self; sc->mii_inst = mii->mii_instance; sc->mii_phy = ma->mii_phyno; sc->mii_funcs = &ihphy_funcs; sc->mii_pdata = mii; sc->mii_flags = ma->mii_flags; sc->mii_anegticks = MII_ANEGTICKS; PHY_RESET(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); aprint_normal_dev(self, ""); if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) aprint_error("no media present"); else mii_phy_add_media(sc); aprint_normal("\n"); /* * Link setup (as done by Intel's Linux driver for the 82577). */ reg = PHY_READ(sc, IHPHY_MII_CFG); reg |= IHPHY_CFG_TX_CRS; reg |= IHPHY_CFG_DOWN_SHIFT; PHY_WRITE(sc, IHPHY_MII_CFG, reg); }
static void rgephy_loop(struct mii_softc *sc) { int i; if (sc->mii_mpd_rev < 2) { PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN); DELAY(1000); } for (i = 0; i < 15000; i++) { if (!(PHY_READ(sc, RGEPHY_MII_BMSR) & RGEPHY_BMSR_LINK)) { #if 0 device_printf(sc->mii_dev, "looped %d\n", i); #endif break; } DELAY(10); } }
static void rgephy_reset(struct mii_softc *sc) { struct rgephy_softc *rsc; uint16_t ssr; rsc = (struct rgephy_softc *)sc; if (rsc->mii_revision == 3) { /* RTL8211C(L) */ ssr = PHY_READ(sc, RGEPHY_MII_SSR); if ((ssr & RGEPHY_SSR_ALDPS) != 0) { ssr &= ~RGEPHY_SSR_ALDPS; PHY_WRITE(sc, RGEPHY_MII_SSR, ssr); } } mii_phy_reset(sc); DELAY(1000); rgephy_load_dspcode(sc); }
void ipgphy_reset(struct mii_softc *sc) { struct ifnet *ifp = sc->mii_pdata->mii_ifp; struct stge_softc *stge_sc; uint32_t reg; mii_phy_reset(sc); /* clear autoneg/full-duplex as we don't want it after reset */ reg = PHY_READ(sc, IPGPHY_MII_BMCR); reg &= ~(IPGPHY_BMCR_AUTOEN | IPGPHY_BMCR_FDX); PHY_WRITE(sc, MII_BMCR, reg); if (sc->mii_model == MII_MODEL_ICPLUS_IP1000A && strcmp(ifp->if_xname, "stge") == 0) { stge_sc = ifp->if_softc; if (stge_sc->sc_rev >= 0x40 && stge_sc->sc_rev <= 0x4e) ipgphy_load_dspcode(sc); } }
static void brgphy_ber_bug(struct mii_softc *sc) { static const struct { int reg; uint16_t val; } dspcode[] = { { BRGPHY_MII_AUXCTL, 0x0c00 }, { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, { BRGPHY_MII_DSP_RW_PORT, 0x310b }, { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, { BRGPHY_MII_AUXCTL, 0x0400 }, { 0, 0 }, }; int i; for (i = 0; dspcode[i].reg != 0; i++) PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); }
void brgphy_bcm5421_dspcode(struct mii_softc *sc) { uint16_t data; /* Set Class A mode */ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); data = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); /* Set FFE gamma override to -0.125 */ PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); data = PHY_READ(sc, BRGPHY_MII_AUXCTL); PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); }
static void e1000phy_reset(struct mii_softc *sc) { u_int32_t reg; int i; /* initialize custom E1000 registers to magic values */ reg = PHY_READ(sc, E1000_SCR); reg &= ~E1000_SCR_AUTO_X_MODE; PHY_WRITE(sc, E1000_SCR, reg); /* normal PHY reset */ /*mii_phy_reset(sc);*/ reg = PHY_READ(sc, E1000_CR); reg |= E1000_CR_RESET; PHY_WRITE(sc, E1000_CR, reg); for (i = 0; i < 500; i++) { DELAY(1); reg = PHY_READ(sc, E1000_CR); if (!(reg & E1000_CR_RESET)) break; } /* set more custom E1000 registers to magic values */ reg = PHY_READ(sc, E1000_SCR); reg |= E1000_SCR_ASSERT_CRS_ON_TX; PHY_WRITE(sc, E1000_SCR, reg); reg = PHY_READ(sc, E1000_ESCR); reg |= E1000_ESCR_TX_CLK_25; PHY_WRITE(sc, E1000_ESCR, reg); /* even more magic to reset DSP? */ PHY_WRITE(sc, 29, 0x1d); PHY_WRITE(sc, 30, 0xc1); PHY_WRITE(sc, 30, 0x00); }
static void brgphy_status(struct mii_softc *sc) { struct brgphy_softc *bsc = (struct brgphy_softc *)sc; struct mii_data *mii = sc->mii_pdata; int aux, bmcr, bmsr, val, xstat; u_int flowstat; mii->mii_media_status = IFM_AVALID; mii->mii_media_active = IFM_ETHER; bmsr = PHY_READ(sc, BRGPHY_MII_BMSR) | PHY_READ(sc, BRGPHY_MII_BMSR); bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); if (bmcr & BRGPHY_BMCR_LOOP) { mii->mii_media_active |= IFM_LOOP; } if ((bmcr & BRGPHY_BMCR_AUTOEN) && (bmsr & BRGPHY_BMSR_ACOMP) == 0 && (bsc->serdes_flags & BRGPHY_NOANWAIT) == 0) { /* Erg, still trying, I guess... */ mii->mii_media_active |= IFM_NONE; return; } if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { /* * NB: reading the ANAR, ANLPAR or 1000STS after the AUXSTS * wedges at least the PHY of BCM5704 (but not others). */ flowstat = mii_phy_flowstatus(sc); xstat = PHY_READ(sc, BRGPHY_MII_1000STS); aux = PHY_READ(sc, BRGPHY_MII_AUXSTS); /* If copper link is up, get the negotiated speed/duplex. */ if (aux & BRGPHY_AUXSTS_LINK) { mii->mii_media_status |= IFM_ACTIVE; switch (aux & BRGPHY_AUXSTS_AN_RES) { case BRGPHY_RES_1000FD: mii->mii_media_active |= IFM_1000_T | IFM_FDX; break; case BRGPHY_RES_1000HD: mii->mii_media_active |= IFM_1000_T | IFM_HDX; break; case BRGPHY_RES_100FD: mii->mii_media_active |= IFM_100_TX | IFM_FDX; break; case BRGPHY_RES_100T4: mii->mii_media_active |= IFM_100_T4; break; case BRGPHY_RES_100HD: mii->mii_media_active |= IFM_100_TX | IFM_HDX; break; case BRGPHY_RES_10FD: mii->mii_media_active |= IFM_10_T | IFM_FDX; break; case BRGPHY_RES_10HD: mii->mii_media_active |= IFM_10_T | IFM_HDX; break; default: mii->mii_media_active |= IFM_NONE; break; } if ((mii->mii_media_active & IFM_FDX) != 0) mii->mii_media_active |= flowstat; if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T && (xstat & BRGPHY_1000STS_MSR) != 0) mii->mii_media_active |= IFM_ETH_MASTER; } } else { /* Todo: Add support for flow control. */ /* If serdes link is up, get the negotiated speed/duplex. */ if (bmsr & BRGPHY_BMSR_LINK) { mii->mii_media_status |= IFM_ACTIVE; } /* Check the link speed/duplex based on the PHY type. */ if (bsc->serdes_flags & BRGPHY_5706S) { mii->mii_media_active |= IFM_1000_SX; /* If autoneg enabled, read negotiated duplex settings */ if (bmcr & BRGPHY_BMCR_AUTOEN) { val = PHY_READ(sc, BRGPHY_SERDES_ANAR) & PHY_READ(sc, BRGPHY_SERDES_ANLPAR); if (val & BRGPHY_SERDES_ANAR_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } } else if (bsc->serdes_flags & BRGPHY_5708S) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); /* Check for MRBE auto-negotiated speed results. */ switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: mii->mii_media_active |= IFM_10_FL; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: mii->mii_media_active |= IFM_100_FX; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: mii->mii_media_active |= IFM_1000_SX; break; case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: mii->mii_media_active |= IFM_2500_SX; break; } /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } else if (bsc->serdes_flags & BRGPHY_5709S) { /* Select GP Status Block of the AN MMD, get autoneg results. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS); xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); /* Restore IEEE0 block (assumed in all brgphy(4) code). */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); /* Check for MRBE auto-negotiated speed results. */ switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: mii->mii_media_active |= IFM_10_FL; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: mii->mii_media_active |= IFM_100_FX; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: mii->mii_media_active |= IFM_1000_SX; break; case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: mii->mii_media_active |= IFM_2500_SX; break; } /* Check for MRBE auto-negotiated duplex results. */ if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX) mii->mii_media_active |= IFM_FDX; else mii->mii_media_active |= IFM_HDX; } } }
/* Attach the PHY to the MII bus */ static int brgphy_attach(device_t dev) { struct brgphy_softc *bsc; struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; struct mii_softc *sc; struct ifnet *ifp; bsc = device_get_softc(dev); sc = &bsc->mii_sc; mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, &brgphy_funcs, 0); bsc->serdes_flags = 0; ifp = sc->mii_pdata->mii_ifp; /* Find the MAC driver associated with this PHY. */ if (strcmp(ifp->if_dname, "bge") == 0) bge_sc = ifp->if_softc; else if (strcmp(ifp->if_dname, "bce") == 0) bce_sc = ifp->if_softc; /* Handle any special cases based on the PHY ID */ switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5706: case MII_MODEL_BROADCOM_BCM5714: /* * The 5464 PHY used in the 5706 supports both copper * and fiber interfaces over GMII. Need to check the * shadow registers to see which mode is actually * in effect, and therefore whether we have 5706C or * 5706S. */ PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_MODE_CTRL); if (PHY_READ(sc, BRGPHY_MII_SHADOW_1C) & BRGPHY_SHADOW_1C_ENA_1000X) { bsc->serdes_flags |= BRGPHY_5706S; sc->mii_flags |= MIIF_HAVEFIBER; } break; } break; case MII_OUI_BROADCOM2: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM2_BCM5708S: bsc->serdes_flags |= BRGPHY_5708S; sc->mii_flags |= MIIF_HAVEFIBER; break; case MII_MODEL_BROADCOM2_BCM5709S: /* * XXX * 5720S and 5709S shares the same PHY id. * Assume 5720S PHY if parent device is bge(4). */ if (bge_sc != NULL) bsc->serdes_flags |= BRGPHY_5708S; else bsc->serdes_flags |= BRGPHY_5709S; sc->mii_flags |= MIIF_HAVEFIBER; break; } break; } PHY_RESET(sc); /* Read the PHY's capabilities. */ sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask; if (sc->mii_capabilities & BMSR_EXTSTAT) sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); device_printf(dev, " "); #define ADD(m, c) ifmedia_add(&sc->mii_pdata->mii_media, (m), (c), NULL) /* Add the supported media types */ if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) { mii_phy_add_media(sc); printf("\n"); } else { sc->mii_anegticks = MII_ANEGTICKS_GIGE; ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst), BRGPHY_S1000 | BRGPHY_BMCR_FDX); printf("1000baseSX-FDX, "); /* 2.5G support is a software enabled feature on the 5708S and 5709S. */ if (bce_sc && (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG)) { ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, IFM_FDX, sc->mii_inst), 0); printf("2500baseSX-FDX, "); } else if ((bsc->serdes_flags & BRGPHY_5708S) && bce_sc && (detect_hs21(bce_sc) != 0)) { /* * There appears to be certain silicon revision * in IBM HS21 blades that is having issues with * this driver wating for the auto-negotiation to * complete. This happens with a specific chip id * only and when the 1000baseSX-FDX is the only * mode. Workaround this issue since it's unlikely * to be ever addressed. */ printf("auto-neg workaround, "); bsc->serdes_flags |= BRGPHY_NOANWAIT; } ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0); printf("auto\n"); } #undef ADD MIIBUS_MEDIAINIT(sc->mii_dev); return (0); }
int atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t anar, bmcr, bmsr; switch (cmd) { case MII_POLLSTAT: /* * If we're not polling our PHY instance, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); break; case MII_MEDIACHG: /* * If the media indicates a different PHY instance, * isolate ourselves. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) { bmcr = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); return (0); } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; bmcr = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: case IFM_1000_T: atphy_mii_phy_auto(sc); goto done; case IFM_100_TX: bmcr = BMCR_S100; break; case IFM_10_T: bmcr = BMCR_S10; break; case IFM_NONE: bmcr = PHY_READ(sc, MII_BMCR); /* * XXX * Due to an unknown reason powering down PHY resulted * in unexpected results such as inaccessibility of * hardware of freshly rebooted system. Disable * powering down PHY until I got more information for * Attansic/Atheros PHY hardwares. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO); goto done; default: return (EINVAL); } anar = mii_anar(ife->ifm_media); if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) { bmcr |= BMCR_FDX; /* Enable pause. */ if (sc->mii_flags & MIIF_DOPAUSE) anar |= ANAR_PAUSE_TOWARDS; } if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) PHY_WRITE(sc, MII_100T2CR, 0); PHY_WRITE(sc, MII_ANAR, anar); /* * Reset the PHY so all changes take effect. */ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG); done: break; case MII_TICK: /* * If we're not currently selected, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * Check for link. * Read the status register twice; BMSR_LINK is latch-low. */ bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (bmsr & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; /* * Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; atphy_mii_phy_auto(sc); break; } /* Update the media status. */ mii_phy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static int smcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife; int reg; ife = mii->mii_media.ifm_cur; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: smcphy_auto(sc, ife->ifm_media); break; default: mii_phy_setmedia(sc); break; } break; case MII_TICK: if ((mii->mii_ifp->if_flags & IFF_UP) == 0) { return (0); } if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { break; } /* I have no idea why BMCR_ISO gets set. */ reg = PHY_READ(sc, MII_BMCR); if (reg & BMCR_ISO) { PHY_WRITE(sc, MII_BMCR, reg & ~BMCR_ISO); } reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) { sc->mii_ticks = 0; break; } if (++sc->mii_ticks <= MII_ANEGTICKS) { break; } sc->mii_ticks = 0; PHY_RESET(sc); smcphy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
int xmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0) return (ENXIO); switch (cmd) { case MII_POLLSTAT: /* * If we're not polling our PHY instance, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); break; case MII_MEDIACHG: /* * If the media indicates a different PHY instance, * isolate ourselves. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) { reg = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); return (0); } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: (void) xmphy_mii_phy_auto(sc); break; case IFM_1000_SX: PHY_RESET(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_FDX); PHY_WRITE(sc, XMPHY_MII_BMCR, XMPHY_BMCR_FDX); } else { PHY_WRITE(sc, XMPHY_MII_ANAR, XMPHY_ANAR_HDX); PHY_WRITE(sc, XMPHY_MII_BMCR, 0); } break; case IFM_100_T4: case IFM_100_TX: case IFM_10_T: default: return (EINVAL); } break; case MII_TICK: /* * If we're not currently selected, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) break; /* * Only retry autonegotiation every mii_anegticks seconds. */ if (++sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; PHY_RESET(sc); xmphy_mii_phy_auto(sc); break; } /* Update the media status. */ mii_phy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static int igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t reg; switch (cmd) { case MII_POLLSTAT: /* * If we're not polling our PHY instance, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); break; case MII_MEDIACHG: /* * If the media indicates a different PHY instance, * isolate ourselves. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) { reg = PHY_READ(sc, MII_BMCR); PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); return (0); } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL); if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { reg |= PSCR_AUTO_MDIX; reg &= ~PSCR_FORCE_MDI_MDIX; PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); } else { reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX); PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg); } mii_phy_setmedia(sc); break; case MII_TICK: /* * If we're not currently selected, just return. */ if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0); igphy_smartspeed_workaround(sc); if (mii_phy_tick(sc) == EJUSTRETURN) return (0); break; case MII_DOWN: mii_phy_down(sc); return (0); } /* Update the media status. */ mii_phy_status(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static int e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint16_t speed, gig; int reg; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { e1000phy_mii_phy_auto(sc, ife->ifm_media); break; } speed = 0; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_1000_T: if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) == 0) return (EINVAL); speed = E1000_CR_SPEED_1000; break; case IFM_1000_SX: if ((sc->mii_extcapabilities & (EXTSR_1000XFDX | EXTSR_1000XHDX)) == 0) return (EINVAL); speed = E1000_CR_SPEED_1000; break; case IFM_100_TX: speed = E1000_CR_SPEED_100; break; case IFM_10_T: speed = E1000_CR_SPEED_10; break; case IFM_NONE: reg = PHY_READ(sc, E1000_CR); PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE | E1000_CR_POWER_DOWN); goto done; default: return (EINVAL); } if ((ife->ifm_media & IFM_FDX) != 0) { speed |= E1000_CR_FULL_DUPLEX; gig = E1000_1GCR_1000T_FD; } else gig = E1000_1GCR_1000T; reg = PHY_READ(sc, E1000_CR); reg &= ~E1000_CR_AUTO_NEG_ENABLE; PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET); if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= E1000_1GCR_MS_ENABLE; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= E1000_1GCR_MS_VALUE; } else if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0) gig = 0; PHY_WRITE(sc, E1000_1GCR, gig); PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD); PHY_WRITE(sc, E1000_CR, speed | E1000_CR_RESET); done: break; case MII_TICK: /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * check for link. * Read the status register twice; BMSR_LINK is latch-low. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens. */ if (sc->mii_ticks++ == 0) break; if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; PHY_RESET(sc); e1000phy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static int tlphy_service(struct mii_softc *self, struct mii_data *mii, int cmd) { struct tlphy_softc *sc = (struct tlphy_softc *)self; struct ifmedia_entry *ife = mii->mii_media.ifm_cur; int reg; if (sc->sc_need_acomp) tlphy_acomp(sc); switch (cmd) { case MII_POLLSTAT: /* * If we're not polling our PHY instance, just return. */ if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) return (0); break; case MII_MEDIACHG: /* * If the media indicates a different PHY instance, * isolate ourselves. */ if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) { reg = PHY_READ(&sc->sc_mii, MII_BMCR); PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO); return (0); } /* * If the interface is not up, don't do anything. */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: /* * The ThunderLAN PHY doesn't self-configure after * an autonegotiation cycle, so there's no such * thing as "already in auto mode". */ tlphy_auto(sc, 1); break; case IFM_10_2: case IFM_10_5: PHY_WRITE(&sc->sc_mii, MII_BMCR, 0); PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL); DELAY(100000); break; default: PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0); DELAY(100000); mii_phy_set_media(&sc->sc_mii); break; } break; case MII_TICK: /* * If we're not currently selected, just return. */ if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) return (0); /* * Is the interface even up? */ if ((mii->mii_ifp->if_flags & IFF_UP) == 0) return (0); /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) break; /* * Check to see if we have link. If we do, we don't * need to restart the autonegotiation process. Read * the BMSR twice in case it's latched. * * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?! */ reg = PHY_READ(&sc->sc_mii, MII_BMSR) | PHY_READ(&sc->sc_mii, MII_BMSR); if (reg & BMSR_LINK) { sc->sc_mii.mii_ticks = 0; break; } /* * Only retry autonegotiation every mii_anegticks seconds. */ if (++sc->sc_mii.mii_ticks <= sc->sc_mii.mii_anegticks) return (0); sc->sc_mii.mii_ticks = 0; mii_phy_reset(&sc->sc_mii); if (tlphy_auto(sc, 0) == EJUSTRETURN) return (0); break; } /* Update the media status. */ tlphy_status(sc); /* Callback if something changed. */ mii_phy_update(&sc->sc_mii, cmd); return (0); }
static void brgphy_reset(struct mii_softc *sc) { struct bge_softc *bge_sc = NULL; struct bce_softc *bce_sc = NULL; struct ifnet *ifp; int i, val; /* * Perform a reset. Note that at least some Broadcom PHYs default to * being powered down as well as isolated after a reset but don't work * if one or both of these bits are cleared. However, they just work * fine if both bits remain set, so we don't use mii_phy_reset() here. */ PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_RESET); /* Wait 100ms for it to complete. */ for (i = 0; i < 100; i++) { if ((PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_RESET) == 0) break; DELAY(1000); } /* Handle any PHY specific procedures following the reset. */ switch (sc->mii_mpd_oui) { case MII_OUI_BROADCOM: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM_BCM5400: bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5401: if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) bcm5401_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM5411: bcm5411_load_dspcode(sc); break; case MII_MODEL_BROADCOM_BCM54K2: bcm54k2_load_dspcode(sc); break; } break; case MII_OUI_BROADCOM3: switch (sc->mii_mpd_model) { case MII_MODEL_BROADCOM3_BCM5717C: case MII_MODEL_BROADCOM3_BCM5719C: case MII_MODEL_BROADCOM3_BCM5720C: case MII_MODEL_BROADCOM3_BCM57765: return; } break; case MII_OUI_BROADCOM4: return; } ifp = sc->mii_pdata->mii_ifp; /* Find the driver associated with this PHY. */ if (strcmp(ifp->if_dname, "bge") == 0) { bge_sc = ifp->if_softc; } else if (strcmp(ifp->if_dname, "bce") == 0) { bce_sc = ifp->if_softc; } if (bge_sc) { /* Fix up various bugs */ if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG) brgphy_fixup_5704_a0_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG) brgphy_fixup_adc_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) brgphy_fixup_adjust_trim(sc); if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG) brgphy_fixup_ber_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG) brgphy_fixup_crc_bug(sc); if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) brgphy_fixup_jitter_bug(sc); if (bge_sc->bge_flags & BGE_FLAG_JUMBO) brgphy_jumbo_settings(sc, ifp->if_mtu); if ((bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED) == 0) brgphy_ethernet_wirespeed(sc); /* Enable Link LED on Dell boxes */ if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) { PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) & ~BRGPHY_PHY_EXTCTL_3_LED); } /* Adjust output voltage (From Linux driver) */ if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5906) PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); } else if (bce_sc) { if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5708 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { /* Store autoneg capabilities/results in digital block (Page 0) */ PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); /* Enable fiber mode and autodetection */ PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); /* Enable parallel detection */ PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); /* Advertise 2.5G support through next page during autoneg */ if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); /* Increase TX signal amplitude */ if ((BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_A0) || (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B0) || (BCE_CHIP_ID(bce_sc) == BCE_CHIP_ID_5708_B1)) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_TX_MISC_PG5); PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & ~0x30); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); } /* Backplanes use special driver/pre-driver/pre-emphasis values. */ if ((bce_sc->bce_shared_hw_cfg & BCE_SHARED_HW_CFG_PHY_BACKPLANE) && (bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK)) { PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_TX_MISC_PG5); PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, bce_sc->bce_port_hw_cfg & BCE_PORT_HW_CFG_CFG_TXCTL3_MASK); PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); } } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709 && (bce_sc->bce_phy_flags & BCE_PHY_SERDES_FLAG)) { /* Select the SerDes Digital block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG); val = PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1); val &= ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET; val |= BRGPHY_SD_DIG_1000X_CTL1_FIBER; PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, val); /* Select the Over 1G block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_OVER_1G); /* Enable autoneg "Next Page" to advertise 2.5G support. */ val = PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1); if (bce_sc->bce_phy_flags & BCE_PHY_2_5G_CAPABLE_FLAG) val |= BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; else val &= ~BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G; PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, val); /* Select the Multi-Rate Backplane Ethernet block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE); /* Enable MRBE speed autoneg. */ val = PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP); val |= BRGPHY_MRBE_MSG_PG5_NP_MBRE | BRGPHY_MRBE_MSG_PG5_NP_T2; PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, val); /* Select the Clause 73 User B0 block of the AN MMD. */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_CL73_USER_B0); /* Enable MRBE speed autoneg. */ PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); /* Restore IEEE0 block (assumed in all brgphy(4) code). */ PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); } else if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709) { if ((BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Ax) || (BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Bx)) brgphy_fixup_disable_early_dac(sc); brgphy_jumbo_settings(sc, ifp->if_mtu); brgphy_ethernet_wirespeed(sc); } else { brgphy_fixup_ber_bug(sc); brgphy_jumbo_settings(sc, ifp->if_mtu); brgphy_ethernet_wirespeed(sc); } } }
static void bwi_phy_init_11b_rev5(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; struct bwi_rf *rf = &mac->mac_rf; struct bwi_phy *phy = &mac->mac_phy; u_int orig_chan; if (phy->phy_version == 1) RF_SETBITS(mac, 0x7a, 0x50); if (sc->sc_pci_subvid != PCI_VENDOR_BROADCOM && sc->sc_pci_subdid != BWI_PCI_SUBDEVICE_BU4306) { uint16_t ofs, val; val = 0x2120; for (ofs = 0xa8; ofs < 0xc7; ++ofs) { PHY_WRITE(mac, ofs, val); val += 0x202; } } PHY_FILT_SETBITS(mac, 0x35, 0xf0ff, 0x700); if (rf->rf_type == BWI_RF_T_BCM2050) PHY_WRITE(mac, 0x38, 0x667); if ((phy->phy_flags & BWI_PHY_F_LINKED) || phy->phy_rev >= 2) { if (rf->rf_type == BWI_RF_T_BCM2050) { RF_SETBITS(mac, 0x7a, 0x20); RF_SETBITS(mac, 0x51, 0x4); } CSR_WRITE_2(sc, BWI_RF_ANTDIV, 0); PHY_SETBITS(mac, 0x802, 0x100); PHY_SETBITS(mac, 0x42b, 0x2000); PHY_WRITE(mac, 0x1c, 0x186a); PHY_FILT_SETBITS(mac, 0x13, 0xff, 0x1900); PHY_FILT_SETBITS(mac, 0x35, 0xffc0, 0x64); PHY_FILT_SETBITS(mac, 0x5d, 0xff80, 0xa); } /* TODO: bad_frame_preempt? */ if (phy->phy_version == 1) { PHY_WRITE(mac, 0x26, 0xce00); PHY_WRITE(mac, 0x21, 0x3763); PHY_WRITE(mac, 0x22, 0x1bc3); PHY_WRITE(mac, 0x23, 0x6f9); PHY_WRITE(mac, 0x24, 0x37e); } else { PHY_WRITE(mac, 0x26, 0xcc00); } PHY_WRITE(mac, 0x30, 0xc6); CSR_WRITE_2(sc, BWI_BPHY_CTRL, BWI_BPHY_CTRL_INIT); if (phy->phy_version == 1) PHY_WRITE(mac, 0x20, 0x3e1c); else PHY_WRITE(mac, 0x20, 0x301c); if (phy->phy_version == 0) CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL1); /* Force to channel 7 */ orig_chan = rf->rf_curchan; bwi_rf_set_chan(mac, 7, 0); if (rf->rf_type != BWI_RF_T_BCM2050) { RF_WRITE(mac, 0x75, 0x80); RF_WRITE(mac, 0x79, 0x81); } RF_WRITE(mac, 0x50, 0x20); RF_WRITE(mac, 0x50, 0x23); if (rf->rf_type == BWI_RF_T_BCM2050) { RF_WRITE(mac, 0x50, 0x20); RF_WRITE(mac, 0x5a, 0x70); } RF_WRITE(mac, 0x5b, 0x7b); RF_WRITE(mac, 0x5c, 0xb0); RF_SETBITS(mac, 0x7a, 0x7); bwi_rf_set_chan(mac, orig_chan, 0); PHY_WRITE(mac, 0x14, 0x80); PHY_WRITE(mac, 0x32, 0xca); PHY_WRITE(mac, 0x2a, 0x88a3); bwi_mac_set_tpctl_11bg(mac, NULL); if (rf->rf_type == BWI_RF_T_BCM2050) RF_WRITE(mac, 0x5d, 0xd); CSR_FILT_SETBITS_2(sc, BWI_PHY_MAGIC_REG1, 0xffc0, 0x4); }
static void e1000phy_reset(struct mii_softc *sc) { uint16_t reg, page; reg = PHY_READ(sc, E1000_SCR); if ((sc->mii_flags & MIIF_HAVEFIBER) != 0) { reg &= ~E1000_SCR_AUTO_X_MODE; PHY_WRITE(sc, E1000_SCR, reg); if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1112) { /* Select 1000BASE-X only mode. */ page = PHY_READ(sc, E1000_EADR); PHY_WRITE(sc, E1000_EADR, 2); reg = PHY_READ(sc, E1000_SCR); reg &= ~E1000_SCR_MODE_MASK; reg |= E1000_SCR_MODE_1000BX; PHY_WRITE(sc, E1000_SCR, reg); if ((sc->mii_flags & MIIF_PHYPRIV0) != 0) { /* Set SIGDET polarity low for SFP module. */ PHY_WRITE(sc, E1000_EADR, 1); reg = PHY_READ(sc, E1000_SCR); reg |= E1000_SCR_FIB_SIGDET_POLARITY; PHY_WRITE(sc, E1000_SCR, reg); } PHY_WRITE(sc, E1000_EADR, page); } } else { switch (sc->mii_mpd_model) { case MII_MODEL_xxMARVELL_E1111: case MII_MODEL_xxMARVELL_E1112: case MII_MODEL_xxMARVELL_E1116: case MII_MODEL_xxMARVELL_E1118: case MII_MODEL_xxMARVELL_E1149: case MII_MODEL_xxMARVELL_E1149R: case MII_MODEL_xxMARVELL_PHYG65G: /* Disable energy detect mode. */ reg &= ~E1000_SCR_EN_DETECT_MASK; reg |= E1000_SCR_AUTO_X_MODE; if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116) reg &= ~E1000_SCR_POWER_DOWN; reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; case MII_MODEL_xxMARVELL_E3082: reg |= (E1000_SCR_AUTO_X_MODE >> 1); reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; case MII_MODEL_xxMARVELL_E3016: reg |= E1000_SCR_AUTO_MDIX; reg &= ~(E1000_SCR_EN_DETECT | E1000_SCR_SCRAMBLER_DISABLE); reg |= E1000_SCR_LPNP; /* XXX Enable class A driver for Yukon FE+ A0. */ PHY_WRITE(sc, 0x1C, PHY_READ(sc, 0x1C) | 0x0001); break; default: reg &= ~E1000_SCR_AUTO_X_MODE; reg |= E1000_SCR_ASSERT_CRS_ON_TX; break; } if (sc->mii_mpd_model != MII_MODEL_xxMARVELL_E3016) { /* Auto correction for reversed cable polarity. */ reg &= ~E1000_SCR_POLARITY_REVERSAL; } PHY_WRITE(sc, E1000_SCR, reg); if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116 || sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149 || sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149R) { PHY_WRITE(sc, E1000_EADR, 2); reg = PHY_READ(sc, E1000_SCR); reg |= E1000_SCR_RGMII_POWER_UP; PHY_WRITE(sc, E1000_SCR, reg); PHY_WRITE(sc, E1000_EADR, 0); } } switch (sc->mii_mpd_model) { case MII_MODEL_xxMARVELL_E3082: case MII_MODEL_xxMARVELL_E1112: case MII_MODEL_xxMARVELL_E1118: break; case MII_MODEL_xxMARVELL_E1116: page = PHY_READ(sc, E1000_EADR); /* Select page 3, LED control register. */ PHY_WRITE(sc, E1000_EADR, 3); PHY_WRITE(sc, E1000_SCR, E1000_SCR_LED_LOS(1) | /* Link/Act */ E1000_SCR_LED_INIT(8) | /* 10Mbps */ E1000_SCR_LED_STAT1(7) | /* 100Mbps */ E1000_SCR_LED_STAT0(7)); /* 1000Mbps */ /* Set blink rate. */ PHY_WRITE(sc, E1000_IER, E1000_PULSE_DUR(E1000_PULSE_170MS) | E1000_BLINK_RATE(E1000_BLINK_84MS)); PHY_WRITE(sc, E1000_EADR, page); break; case MII_MODEL_xxMARVELL_E3016: /* LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED. */ PHY_WRITE(sc, 0x16, 0x0B << 8 | 0x05 << 4 | 0x04); /* Integrated register calibration workaround. */ PHY_WRITE(sc, 0x1D, 17); PHY_WRITE(sc, 0x1E, 0x3F60); break; default: /* Force TX_CLK to 25MHz clock. */ reg = PHY_READ(sc, E1000_ESCR); reg |= E1000_ESCR_TX_CLK_25; PHY_WRITE(sc, E1000_ESCR, reg); break; } /* Reset the PHY so all changes take effect. */ reg = PHY_READ(sc, E1000_CR); reg |= E1000_CR_RESET; PHY_WRITE(sc, E1000_CR, reg); }
static void bwi_phy_init_11b_rev6(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; struct bwi_rf *rf = &mac->mac_rf; struct bwi_phy *phy = &mac->mac_phy; uint16_t val, ofs; u_int orig_chan; PHY_WRITE(mac, 0x3e, 0x817a); RF_SETBITS(mac, 0x7a, 0x58); if (rf->rf_rev == 4 || rf->rf_rev == 5) { RF_WRITE(mac, 0x51, 0x37); RF_WRITE(mac, 0x52, 0x70); RF_WRITE(mac, 0x53, 0xb3); RF_WRITE(mac, 0x54, 0x9b); RF_WRITE(mac, 0x5a, 0x88); RF_WRITE(mac, 0x5b, 0x88); RF_WRITE(mac, 0x5d, 0x88); RF_WRITE(mac, 0x5e, 0x88); RF_WRITE(mac, 0x7d, 0x88); HFLAGS_SETBITS(mac, BWI_HFLAG_MAGIC1); } else if (rf->rf_rev == 8) { RF_WRITE(mac, 0x51, 0); RF_WRITE(mac, 0x52, 0x40); RF_WRITE(mac, 0x53, 0xb7); RF_WRITE(mac, 0x54, 0x98); RF_WRITE(mac, 0x5a, 0x88); RF_WRITE(mac, 0x5b, 0x6b); RF_WRITE(mac, 0x5c, 0xf); if (sc->sc_card_flags & BWI_CARD_F_ALT_IQ) { RF_WRITE(mac, 0x5d, 0xfa); RF_WRITE(mac, 0x5e, 0xd8); } else { RF_WRITE(mac, 0x5d, 0xf5); RF_WRITE(mac, 0x5e, 0xb8); } RF_WRITE(mac, 0x73, 0x3); RF_WRITE(mac, 0x7d, 0xa8); RF_WRITE(mac, 0x7c, 0x1); RF_WRITE(mac, 0x7e, 0x8); } val = 0x1e1f; for (ofs = 0x88; ofs < 0x98; ++ofs) { PHY_WRITE(mac, ofs, val); val -= 0x202; } val = 0x3e3f; for (ofs = 0x98; ofs < 0xa8; ++ofs) { PHY_WRITE(mac, ofs, val); val -= 0x202; } val = 0x2120; for (ofs = 0xa8; ofs < 0xc8; ++ofs) { PHY_WRITE(mac, ofs, (val & 0x3f3f)); val += 0x202; /* XXX: delay 10 us to avoid PCI parity errors with BCM4318 */ DELAY(10); } if (phy->phy_mode == IEEE80211_MODE_11G) { RF_SETBITS(mac, 0x7a, 0x20); RF_SETBITS(mac, 0x51, 0x4); PHY_SETBITS(mac, 0x802, 0x100); PHY_SETBITS(mac, 0x42b, 0x2000); PHY_WRITE(mac, 0x5b, 0); PHY_WRITE(mac, 0x5c, 0); } /* Force to channel 7 */ orig_chan = rf->rf_curchan; if (orig_chan >= 8) bwi_rf_set_chan(mac, 1, 0); else bwi_rf_set_chan(mac, 13, 0); RF_WRITE(mac, 0x50, 0x20); RF_WRITE(mac, 0x50, 0x23); DELAY(40); if (rf->rf_rev < 6 || rf->rf_rev == 8) { RF_SETBITS(mac, 0x7c, 0x2); RF_WRITE(mac, 0x50, 0x20); } if (rf->rf_rev <= 2) { RF_WRITE(mac, 0x7c, 0x20); RF_WRITE(mac, 0x5a, 0x70); RF_WRITE(mac, 0x5b, 0x7b); RF_WRITE(mac, 0x5c, 0xb0); } RF_FILT_SETBITS(mac, 0x7a, 0xf8, 0x7); bwi_rf_set_chan(mac, orig_chan, 0); PHY_WRITE(mac, 0x14, 0x200); if (rf->rf_rev >= 6) PHY_WRITE(mac, 0x2a, 0x88c2); else PHY_WRITE(mac, 0x2a, 0x8ac0); PHY_WRITE(mac, 0x38, 0x668); bwi_mac_set_tpctl_11bg(mac, NULL); if (rf->rf_rev <= 5) { PHY_FILT_SETBITS(mac, 0x5d, 0xff80, 0x3); if (rf->rf_rev <= 2) RF_WRITE(mac, 0x5d, 0xd); } if (phy->phy_version == 4) { CSR_WRITE_2(sc, BWI_PHY_MAGIC_REG1, BWI_PHY_MAGIC_REG1_VAL2); PHY_CLRBITS(mac, 0x61, 0xf000); } else { PHY_FILT_SETBITS(mac, 0x2, 0xffc0, 0x4); } if (phy->phy_mode == IEEE80211_MODE_11B) { CSR_WRITE_2(sc, BWI_BBP_ATTEN, BWI_BBP_ATTEN_MAGIC2); PHY_WRITE(mac, 0x16, 0x410); PHY_WRITE(mac, 0x17, 0x820); PHY_WRITE(mac, 0x62, 0x7); bwi_rf_init_bcm2050(mac); bwi_rf_lo_update(mac); if (sc->sc_card_flags & BWI_CARD_F_SW_NRSSI) { bwi_rf_calc_nrssi_slope(mac); bwi_rf_set_nrssi_thr(mac); } bwi_mac_init_tpctl_11bg(mac); } else { CSR_WRITE_2(sc, BWI_BBP_ATTEN, 0); } }
static int ip1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; uint32_t gig, reg, speed; switch (cmd) { case MII_POLLSTAT: break; case MII_MEDIACHG: PHY_RESET(sc); switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: (void)ip1000phy_mii_phy_auto(sc, ife->ifm_media); goto done; case IFM_1000_T: /* * XXX * Manual 1000baseT setting doesn't seem to work. */ speed = IP1000PHY_BMCR_1000; break; case IFM_100_TX: speed = IP1000PHY_BMCR_100; break; case IFM_10_T: speed = IP1000PHY_BMCR_10; break; default: return (EINVAL); } if ((ife->ifm_media & IFM_FDX) != 0) { speed |= IP1000PHY_BMCR_FDX; gig = IP1000PHY_1000CR_1000T_FDX; } else gig = IP1000PHY_1000CR_1000T; if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) { gig |= IP1000PHY_1000CR_MASTER | IP1000PHY_1000CR_MANUAL; if ((ife->ifm_media & IFM_ETH_MASTER) != 0) gig |= IP1000PHY_1000CR_MMASTER; } else gig = 0; PHY_WRITE(sc, IP1000PHY_MII_1000CR, gig); PHY_WRITE(sc, IP1000PHY_MII_BMCR, speed); done: break; case MII_TICK: /* * Only used for autonegotiation. */ if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) { sc->mii_ticks = 0; break; } /* * check for link. */ reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); if (reg & BMSR_LINK) { sc->mii_ticks = 0; break; } /* Announce link loss right after it happens */ if (sc->mii_ticks++ == 0) break; /* * Only retry autonegotiation every mii_anegticks seconds. */ if (sc->mii_ticks <= sc->mii_anegticks) break; sc->mii_ticks = 0; ip1000phy_mii_phy_auto(sc, ife->ifm_media); break; } /* Update the media status. */ PHY_STATUS(sc); /* Callback if something changed. */ mii_phy_update(sc, cmd); return (0); }
static void bwi_phy_config_11g(struct bwi_mac *mac) { struct bwi_softc *sc = mac->mac_sc; struct bwi_phy *phy = &mac->mac_phy; const uint16_t *tbl; uint16_t wrd_ofs1, wrd_ofs2; int i, n; if (phy->phy_rev == 1) { PHY_WRITE(mac, 0x406, 0x4f19); PHY_FILT_SETBITS(mac, 0x429, 0xfc3f, 0x340); PHY_WRITE(mac, 0x42c, 0x5a); PHY_WRITE(mac, 0x427, 0x1a); /* Fill frequency table */ for (i = 0; i < N(bwi_phy_freq_11g_rev1); ++i) { bwi_tbl_write_2(mac, BWI_PHYTBL_FREQ + i, bwi_phy_freq_11g_rev1[i]); } /* Fill noise table */ for (i = 0; i < N(bwi_phy_noise_11g_rev1); ++i) { bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i, bwi_phy_noise_11g_rev1[i]); } /* Fill rotor table */ for (i = 0; i < N(bwi_phy_rotor_11g_rev1); ++i) { /* NB: data length is 4 bytes */ bwi_tbl_write_4(mac, BWI_PHYTBL_ROTOR + i, bwi_phy_rotor_11g_rev1[i]); } } else { bwi_nrssi_write(mac, 0xba98, (int16_t)0x7654); /* XXX */ if (phy->phy_rev == 2) { PHY_WRITE(mac, 0x4c0, 0x1861); PHY_WRITE(mac, 0x4c1, 0x271); } else if (phy->phy_rev > 2) { PHY_WRITE(mac, 0x4c0, 0x98); PHY_WRITE(mac, 0x4c1, 0x70); PHY_WRITE(mac, 0x4c9, 0x80); } PHY_SETBITS(mac, 0x42b, 0x800); /* Fill RSSI table */ for (i = 0; i < 64; ++i) bwi_tbl_write_2(mac, BWI_PHYTBL_RSSI + i, i); /* Fill noise table */ for (i = 0; i < sizeof(bwi_phy_noise_11g); ++i) { bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE + i, bwi_phy_noise_11g[i]); } } /* * Fill noise scale table */ if (phy->phy_rev <= 2) { tbl = bwi_phy_noise_scale_11g_rev2; n = N(bwi_phy_noise_scale_11g_rev2); } else if (phy->phy_rev >= 7 && (PHY_READ(mac, 0x449) & 0x200)) { tbl = bwi_phy_noise_scale_11g_rev7; n = N(bwi_phy_noise_scale_11g_rev7); } else { tbl = bwi_phy_noise_scale_11g; n = N(bwi_phy_noise_scale_11g); } for (i = 0; i < n; ++i) bwi_tbl_write_2(mac, BWI_PHYTBL_NOISE_SCALE + i, tbl[i]); /* * Fill sigma square table */ if (phy->phy_rev == 2) { tbl = bwi_phy_sigma_sq_11g_rev2; n = N(bwi_phy_sigma_sq_11g_rev2); } else if (phy->phy_rev > 2 && phy->phy_rev <= 8) { tbl = bwi_phy_sigma_sq_11g_rev7; n = N(bwi_phy_sigma_sq_11g_rev7); } else { tbl = NULL; n = 0; } for (i = 0; i < n; ++i) bwi_tbl_write_2(mac, BWI_PHYTBL_SIGMA_SQ + i, tbl[i]); if (phy->phy_rev == 1) { /* Fill delay table */ for (i = 0; i < N(bwi_phy_delay_11g_rev1); ++i) { bwi_tbl_write_4(mac, BWI_PHYTBL_DELAY + i, bwi_phy_delay_11g_rev1[i]); } /* Fill WRSSI (Wide-Band RSSI) table */ for (i = 4; i < 20; ++i) bwi_tbl_write_2(mac, BWI_PHYTBL_WRSSI_REV1 + i, 0x20); bwi_phy_config_agc(mac); wrd_ofs1 = 0x5001; wrd_ofs2 = 0x5002; } else { /* Fill WRSSI (Wide-Band RSSI) table */ for (i = 0; i < 0x20; ++i) bwi_tbl_write_2(mac, BWI_PHYTBL_WRSSI + i, 0x820); bwi_phy_config_agc(mac); PHY_READ(mac, 0x400); /* Dummy read */ PHY_WRITE(mac, 0x403, 0x1000); bwi_tbl_write_2(mac, 0x3c02, 0xf); bwi_tbl_write_2(mac, 0x3c03, 0x14); wrd_ofs1 = 0x401; wrd_ofs2 = 0x402; } if (!(BWI_IS_BRCM_BU4306(sc) && sc->sc_pci_revid == 0x17)) { bwi_tbl_write_2(mac, wrd_ofs1, 0x2); bwi_tbl_write_2(mac, wrd_ofs2, 0x1); } /* phy->phy_flags & BWI_PHY_F_LINKED ? */ if (sc->sc_card_flags & BWI_CARD_F_PA_GPIO9) PHY_WRITE(mac, 0x46e, 0x3cf); }
static void micphy_write(struct mii_softc *sc, uint32_t reg, uint32_t val) { PHY_WRITE(sc, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | reg); PHY_WRITE(sc, MII_KSZPHY_EXTREG_WRITE, val); }
/* * Configure Automatic Gain Controller */ static void bwi_phy_config_agc(struct bwi_mac *mac) { struct bwi_phy *phy = &mac->mac_phy; uint16_t ofs; ofs = phy->phy_rev == 1 ? 0x4c00 : 0; bwi_tbl_write_2(mac, ofs, 0xfe); bwi_tbl_write_2(mac, ofs + 1, 0xd); bwi_tbl_write_2(mac, ofs + 2, 0x13); bwi_tbl_write_2(mac, ofs + 3, 0x19); if (phy->phy_rev == 1) { bwi_tbl_write_2(mac, 0x1800, 0x2710); bwi_tbl_write_2(mac, 0x1801, 0x9b83); bwi_tbl_write_2(mac, 0x1802, 0x9b83); bwi_tbl_write_2(mac, 0x1803, 0xf8d); PHY_WRITE(mac, 0x455, 0x4); } PHY_FILT_SETBITS(mac, 0x4a5, 0xff, 0x5700); PHY_FILT_SETBITS(mac, 0x41a, 0xff80, 0xf); PHY_FILT_SETBITS(mac, 0x41a, 0xc07f, 0x2b80); PHY_FILT_SETBITS(mac, 0x48c, 0xf0ff, 0x300); RF_SETBITS(mac, 0x7a, 0x8); PHY_FILT_SETBITS(mac, 0x4a0, 0xfff0, 0x8); PHY_FILT_SETBITS(mac, 0x4a1, 0xf0ff, 0x600); PHY_FILT_SETBITS(mac, 0x4a2, 0xf0ff, 0x700); PHY_FILT_SETBITS(mac, 0x4a0, 0xf0ff, 0x100); if (phy->phy_rev == 1) PHY_FILT_SETBITS(mac, 0x4a2, 0xfff0, 0x7); PHY_FILT_SETBITS(mac, 0x488, 0xff00, 0x1c); PHY_FILT_SETBITS(mac, 0x488, 0xc0ff, 0x200); PHY_FILT_SETBITS(mac, 0x496, 0xff00, 0x1c); PHY_FILT_SETBITS(mac, 0x489, 0xff00, 0x20); PHY_FILT_SETBITS(mac, 0x489, 0xc0ff, 0x200); PHY_FILT_SETBITS(mac, 0x482, 0xff00, 0x2e); PHY_FILT_SETBITS(mac, 0x496, 0xff, 0x1a00); PHY_FILT_SETBITS(mac, 0x481, 0xff00, 0x28); PHY_FILT_SETBITS(mac, 0x481, 0xff, 0x2c00); if (phy->phy_rev == 1) { PHY_WRITE(mac, 0x430, 0x92b); PHY_FILT_SETBITS(mac, 0x41b, 0xffe1, 0x2); } else { PHY_CLRBITS(mac, 0x41b, 0x1e); PHY_WRITE(mac, 0x41f, 0x287a); PHY_FILT_SETBITS(mac, 0x420, 0xfff0, 0x4); if (phy->phy_rev >= 6) { PHY_WRITE(mac, 0x422, 0x287a); PHY_FILT_SETBITS(mac, 0x420, 0xfff, 0x3000); } } PHY_FILT_SETBITS(mac, 0x4a8, 0x8080, 0x7874); PHY_WRITE(mac, 0x48e, 0x1c00); if (phy->phy_rev == 1) { PHY_FILT_SETBITS(mac, 0x4ab, 0xf0ff, 0x600); PHY_WRITE(mac, 0x48b, 0x5e); PHY_FILT_SETBITS(mac, 0x48c, 0xff00, 0x1e); PHY_WRITE(mac, 0x48d, 0x2); } bwi_tbl_write_2(mac, ofs + 0x800, 0); bwi_tbl_write_2(mac, ofs + 0x801, 7); bwi_tbl_write_2(mac, ofs + 0x802, 16); bwi_tbl_write_2(mac, ofs + 0x803, 28); if (phy->phy_rev >= 6) { PHY_CLRBITS(mac, 0x426, 0x3); PHY_CLRBITS(mac, 0x426, 0x1000); } }