Esempio n. 1
0
static void
brgphy_reset(struct mii_softc *sc)
{
    struct bge_softc *bge_sc = NULL;
    struct bce_softc *bce_sc = NULL;
    if_t 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 (mii_phy_mac_match(sc, "bge"))
        bge_sc = mii_phy_mac_softc(sc);
    else if (mii_phy_mac_match(sc, "bce"))
        bce_sc = mii_phy_mac_softc(sc);

    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, if_getmtu(ifp));

        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, if_getmtu(ifp));
            brgphy_ethernet_wirespeed(sc);
        } else {
            brgphy_fixup_ber_bug(sc);
            brgphy_jumbo_settings(sc, if_getmtu(ifp));
            brgphy_ethernet_wirespeed(sc);
        }
    }
}
Esempio n. 2
0
static int
nsphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
	int reg;

	switch (cmd) {
	case MII_POLLSTAT:
		break;

	case MII_MEDIACHG:
		reg = PHY_READ(sc, MII_NSPHY_PCR);

		/*
		 * Set up the PCR to use LED4 to indicate full-duplex
		 * in both 10baseT and 100baseTX modes.
		 */
		reg |= PCR_LED4MODE;

		/*
		 * Make sure Carrier Integrity Monitor function is
		 * disabled (normal for Node operation, but sometimes
		 * it's not set?!)
		 */
		reg |= PCR_CIMDIS;

		/*
		 * Make sure "force link good" is set to normal mode.
		 * It's only intended for debugging.
		 */
		reg |= PCR_FLINK100;

		/*
		 * Mystery bits which are supposedly `reserved',
		 * but we seem to need to set them when the PHY
		 * is connected to some interfaces:
		 *
		 * 0x0400 is needed for fxp
		 *        (Intel EtherExpress Pro 10+/100B, 82557 chip)
		 *        (nsphy with a DP83840 chip)
		 * 0x0100 may be needed for some other card
		 */
		reg |= 0x0100 | 0x0400;

		if (mii_phy_mac_match(sc, "fxp"))
			PHY_WRITE(sc, MII_NSPHY_PCR, reg);

		mii_phy_setmedia(sc);
		break;

	case MII_TICK:
		if (mii_phy_tick(sc) == EJUSTRETURN)
			return (0);
		break;
	}

	/* Update the media status. */
	PHY_STATUS(sc);

	/* Callback if something changed. */
	mii_phy_update(sc, cmd);
	return (0);
}
Esempio n. 3
0
static void
ciphy_fixup(struct mii_softc *sc)
{
	uint16_t		model;
	uint16_t		status, speed;
	uint16_t		val;

	model = MII_MODEL(PHY_READ(sc, CIPHY_MII_PHYIDR2));
	status = PHY_READ(sc, CIPHY_MII_AUXCSR);
	speed = status & CIPHY_AUXCSR_SPEED;

	if (mii_phy_mac_match(sc, "nfe")) {
		/* need to set for 2.5V RGMII for NVIDIA adapters */
		val = PHY_READ(sc, CIPHY_MII_ECTL1);
		val &= ~(CIPHY_ECTL1_IOVOL | CIPHY_ECTL1_INTSEL);
		val |= (CIPHY_IOVOL_2500MV | CIPHY_INTSEL_RGMII);
		PHY_WRITE(sc, CIPHY_MII_ECTL1, val);
		/* From Linux. */
		val = PHY_READ(sc, CIPHY_MII_AUXCSR);
		val |= CIPHY_AUXCSR_MDPPS;
		PHY_WRITE(sc, CIPHY_MII_AUXCSR, val);
		val = PHY_READ(sc, CIPHY_MII_10BTCSR);
		val |= CIPHY_10BTCSR_ECHO;
		PHY_WRITE(sc, CIPHY_MII_10BTCSR, val);
	}

	switch (model) {
	case MII_MODEL_xxCICADA_CS8204:
	case MII_MODEL_xxCICADA_CS8201:

		/* Turn off "aux mode" (whatever that means) */
		PHY_SETBIT(sc, CIPHY_MII_AUXCSR, CIPHY_AUXCSR_MDPPS);

		/*
		 * Work around speed polling bug in VT3119/VT3216
		 * when using MII in full duplex mode.
		 */
		if ((speed == CIPHY_SPEED10 || speed == CIPHY_SPEED100) &&
		    (status & CIPHY_AUXCSR_FDX)) {
			PHY_SETBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO);
		} else {
			PHY_CLRBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO);
		}

		/* Enable link/activity LED blink. */
		PHY_SETBIT(sc, CIPHY_MII_LED, CIPHY_LED_LINKACTBLINK);

		break;

	case MII_MODEL_xxCICADA_CS8201A:
	case MII_MODEL_xxCICADA_CS8201B:

		/*
		 * Work around speed polling bug in VT3119/VT3216
		 * when using MII in full duplex mode.
		 */
		if ((speed == CIPHY_SPEED10 || speed == CIPHY_SPEED100) &&
		    (status & CIPHY_AUXCSR_FDX)) {
			PHY_SETBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO);
		} else {
			PHY_CLRBIT(sc, CIPHY_MII_10BTCSR, CIPHY_10BTCSR_ECHO);
		}

		break;
	case MII_MODEL_xxCICADA_VSC8211:
	case MII_MODEL_xxCICADA_VSC8221:
	case MII_MODEL_xxCICADA_CS8244:
	case MII_MODEL_xxVITESSE_VSC8601:
	case MII_MODEL_xxVITESSE_VSC8641:
		break;
	default:
		device_printf(sc->mii_dev, "unknown CICADA PHY model %x\n",
		    model);
		break;
	}
}