diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2010-05-24 21:23:24 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2010-05-24 21:23:24 +0000 |
commit | 7981d0a60d42ce13b2507f247abee1bccefd09b0 (patch) | |
tree | 2390d982d5bb12d48ec02de9be36411416a9288e /sys/dev | |
parent | adc81c591b6b23e6d9bd665eb81f389471e1b040 (diff) |
Support fibre PHY on BCM5709S. From FreeBSD via Brad.
Tested by Brad on: BCM5706, BCM5708C
Tested by me on: BCM5716 (BCM5709 PHY)
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/mii/brgphy.c | 119 | ||||
-rw-r--r-- | sys/dev/mii/brgphyreg.h | 57 | ||||
-rw-r--r-- | sys/dev/pci/if_bnx.c | 69 | ||||
-rw-r--r-- | sys/dev/pci/if_bnxreg.h | 3 |
4 files changed, 243 insertions, 5 deletions
diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c index b28da263e35..a7582be86e1 100644 --- a/sys/dev/mii/brgphy.c +++ b/sys/dev/mii/brgphy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: brgphy.c,v 1.92 2010/04/09 22:01:37 sthen Exp $ */ +/* $OpenBSD: brgphy.c,v 1.93 2010/05/24 21:23:23 sthen Exp $ */ /* * Copyright (c) 2000 @@ -81,6 +81,7 @@ int brgphy_service(struct mii_softc *, struct mii_data *, int); void brgphy_copper_status(struct mii_softc *); void brgphy_fiber_status(struct mii_softc *); void brgphy_5708s_status(struct mii_softc *); +void brgphy_5709s_status(struct mii_softc *); int brgphy_mii_phy_auto(struct mii_softc *); void brgphy_loop(struct mii_softc *); void brgphy_reset(struct mii_softc *); @@ -108,6 +109,10 @@ const struct mii_phy_funcs brgphy_5708s_funcs = { brgphy_service, brgphy_5708s_status, brgphy_reset, }; +const struct mii_phy_funcs brgphy_5709s_funcs = { + brgphy_service, brgphy_5709s_status, brgphy_reset, +}; + static const struct mii_phydesc brgphys[] = { { MII_OUI_xxBROADCOM, MII_MODEL_xxBROADCOM_BCM5400, MII_STR_xxBROADCOM_BCM5400 }, @@ -165,6 +170,8 @@ static const struct mii_phydesc brgphys[] = { MII_STR_xxBROADCOM2_BCM5708S }, { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5709C, MII_STR_xxBROADCOM2_BCM5709C }, + { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5709S, + MII_STR_xxBROADCOM2_BCM5709S }, { MII_OUI_xxBROADCOM2, MII_MODEL_xxBROADCOM2_BCM5709CAX, MII_STR_xxBROADCOM2_BCM5709CAX }, { MII_OUI_xxBROADCOM3, MII_MODEL_xxBROADCOM3_BCM57780, @@ -223,6 +230,8 @@ brgphy_attach(struct device *parent, struct device *self, void *aux) if (strcmp(devname, "bnx") == 0) { if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708) sc->mii_funcs = &brgphy_5708s_funcs; + else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709) + sc->mii_funcs = &brgphy_5709s_funcs; else sc->mii_funcs = &brgphy_fiber_funcs; } else @@ -613,6 +622,64 @@ brgphy_5708s_status(struct mii_softc *sc) mii->mii_media_active = ife->ifm_media; } +void +brgphy_5709s_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int bmcr, bmsr; + + 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); + if (bmsr & BRGPHY_BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(sc, BRGPHY_MII_BMCR); + if (bmcr & BRGPHY_BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BRGPHY_BMCR_AUTOEN) { + int xstat; + + if ((bmsr & BRGPHY_BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, + BRGPHY_BLOCK_ADDR_GP_STATUS); + + xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); + + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, + BRGPHY_BLOCK_ADDR_COMBO_IEEE0); + + 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; + } + + if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; + } else + mii->mii_media_active = ife->ifm_media; +} + int brgphy_mii_phy_auto(struct mii_softc *sc) { @@ -796,6 +863,56 @@ brgphy_reset(struct mii_softc *sc) PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); } + } else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709 && + sc->mii_flags & MIIF_HAVEFIBER) { + /* Select the SerDes Digital block of the AN MMD. */ + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, + BRGPHY_BLOCK_ADDR_SERDES_DIG); + + PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, + (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) & + ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) | + BRGPHY_SD_DIG_1000X_CTL1_FIBER); + + if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) { + /* 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. + */ + PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, + PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) | + BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); + } + + /* + * 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. */ + PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, + PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) | + BRGPHY_MRBE_MSG_PG5_NP_MBRE | + BRGPHY_MRBE_MSG_PG5_NP_T2); + + /* 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); + + PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, + BRGPHY_BLOCK_ADDR_COMBO_IEEE0); } else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709) { if (BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Ax || BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Bx) diff --git a/sys/dev/mii/brgphyreg.h b/sys/dev/mii/brgphyreg.h index 7537f0a5077..fece6e9823a 100644 --- a/sys/dev/mii/brgphyreg.h +++ b/sys/dev/mii/brgphyreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: brgphyreg.h,v 1.13 2008/11/08 03:03:50 brad Exp $ */ +/* $OpenBSD: brgphyreg.h,v 1.14 2010/05/24 21:23:23 sthen Exp $ */ /* * Copyright (c) 2000 @@ -369,6 +369,61 @@ /* End: PHY register values for the 5708S SerDes PHY */ /*******************************************************/ +/*******************************************************/ +/* Begin: PHY register values for the 5709S SerDes PHY */ +/*******************************************************/ + +/* 5709S SerDes "General Purpose Status" Registers */ +#define BRGPHY_BLOCK_ADDR_GP_STATUS 0x8120 +#define BRGPHY_GP_STATUS_TOP_ANEG_STATUS 0x1B +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK 0x3F00 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10 0x0000 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100 0x0100 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G 0x0200 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G 0x0300 +#define BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1GKX 0x0D00 +#define BRGPHY_GP_STATUS_TOP_ANEG_FDX 0x0008 +#define BRGPHY_GP_STATUS_TOP_ANEG_LINK_UP 0x0004 +#define BRGPHY_GP_STATUS_TOP_ANEG_CL73_COMP 0x0001 + +/* 5709S SerDes "SerDes Digital" Registers */ +#define BRGPHY_BLOCK_ADDR_SERDES_DIG 0x8300 +#define BRGPHY_SERDES_DIG_1000X_CTL1 0x0010 +#define BRGPHY_SD_DIG_1000X_CTL1_AUTODET 0x0010 +#define BRGPHY_SD_DIG_1000X_CTL1_FIBER 0x0001 + +/* 5709S SerDes "Over 1G" Registers */ +#define BRGPHY_BLOCK_ADDR_OVER_1G 0x8320 +#define BRGPHY_OVER_1G_UNFORMAT_PG1 0x19 + +/* 5709S SerDes "Multi-Rate Backplane Ethernet" Registers */ +#define BRGPHY_BLOCK_ADDR_MRBE 0x8350 +#define BRGPHY_MRBE_MSG_PG5_NP 0x10 +#define BRGPHY_MRBE_MSG_PG5_NP_MBRE 0x0001 +#define BRGPHY_MRBE_MSG_PG5_NP_T2 0x0001 + +/* 5709S SerDes "IEEE Clause 73 User B0" Registers */ +#define BRGPHY_BLOCK_ADDR_CL73_USER_B0 0x8370 +#define BRGPHY_CL73_USER_B0_MBRE_CTL1 0x12 +#define BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP 0x2000 +#define BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR 0x4000 +#define BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG 0x8000 + +/* 5709S SerDes "IEEE Clause 73 User B0" Registers */ +#define BRGPHY_BLOCK_ADDR_ADDR_EXT 0xFFD0 + +/* 5709S SerDes "Combo IEEE 0" Registers */ +#define BRGPHY_BLOCK_ADDR_COMBO_IEEE0 0xFFE0 + +#define BRGPHY_ADDR_EXT 0x1E +#define BRGPHY_BLOCK_ADDR 0x1F + +#define BRGPHY_ADDR_EXT_AN_MMD 0x3800 + +/*******************************************************/ +/* End: PHY register values for the 5709S SerDes PHY */ +/*******************************************************/ + #define BRGPHY_INTRS \ ~(BRGPHY_IMR_LNK_CHG|BRGPHY_IMR_LSP_CHG|BRGPHY_IMR_DUP_CHG) diff --git a/sys/dev/pci/if_bnx.c b/sys/dev/pci/if_bnx.c index 03981d6880f..e87f892e282 100644 --- a/sys/dev/pci/if_bnx.c +++ b/sys/dev/pci/if_bnx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bnx.c,v 1.87 2010/05/19 15:27:35 oga Exp $ */ +/* $OpenBSD: if_bnx.c,v 1.88 2010/05/24 21:23:23 sthen Exp $ */ /*- * Copyright (c) 2006 Broadcom Corporation @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/sys/dev/bce/if_bce.c,v 1.3 2006/04/13 14:12:26 ru Exp $" * BCM5708C B1, B2 * BCM5708S B1, B2 * BCM5709C A1, C0 + * BCM5709S A1, C0 * BCM5716 C0 * * The following controllers are not supported by this driver: @@ -50,7 +51,7 @@ __FBSDID("$FreeBSD: src/sys/dev/bce/if_bce.c,v 1.3 2006/04/13 14:12:26 ru Exp $" * BCM5708C A0, B0 * BCM5708S A0, B0 * BCM5709C A0 B0, B1, B2 (pre-production) - * BCM5709S A0, A1, B0, B1, B2, C0 (pre-production) + * BCM5709S A0, B0, B1, B2 (pre-production) */ #include <dev/pci/if_bnxreg.h> @@ -340,6 +341,7 @@ int bnx_nvram_write(struct bnx_softc *, u_int32_t, u_int8_t *, int); /* */ /****************************************************************************/ void bnx_get_media(struct bnx_softc *); +void bnx_init_media(struct bnx_softc *); int bnx_dma_alloc(struct bnx_softc *); void bnx_dma_free(struct bnx_softc *); void bnx_release_resources(struct bnx_softc *); @@ -905,6 +907,9 @@ bnx_attachhook(void *xsc) sc->bnx_mii.mii_writereg = bnx_miibus_write_reg; sc->bnx_mii.mii_statchg = bnx_miibus_statchg; + /* Handle any special PHY initialization for SerDes PHYs. */ + bnx_init_media(sc); + /* Look for our PHY. */ ifmedia_init(&sc->bnx_mii.mii_media, 0, bnx_ifmedia_upd, bnx_ifmedia_sts); @@ -1120,6 +1125,16 @@ bnx_miibus_read_reg(struct device *dev, int phy, int reg) return(0); } + /* + * The BCM5709S PHY is an IEEE Clause 45 PHY + * with special mappings to work with IEEE + * Clause 22 register accesses. + */ + if ((sc->bnx_phy_flags & BNX_PHY_IEEE_CLAUSE_45_FLAG) != 0) { + if (reg >= MII_BMCR && reg <= MII_ANLPRNP) + reg += 0x10; + } + if (sc->bnx_phy_flags & BNX_PHY_INT_MODE_AUTO_POLLING_FLAG) { val = REG_RD(sc, BNX_EMAC_MDIO_MODE); val &= ~BNX_EMAC_MDIO_MODE_AUTO_POLL; @@ -1199,6 +1214,16 @@ bnx_miibus_write_reg(struct device *dev, int phy, int reg, int val) "val = 0x%04X\n", __FUNCTION__, phy, (u_int16_t) reg & 0xffff, (u_int16_t) val & 0xffff); + /* + * The BCM5709S PHY is an IEEE Clause 45 PHY + * with special mappings to work with IEEE + * Clause 22 register accesses. + */ + if ((sc->bnx_phy_flags & BNX_PHY_IEEE_CLAUSE_45_FLAG) != 0) { + if (reg >= MII_BMCR && reg <= MII_ANLPRNP) + reg += 0x10; + } + if (sc->bnx_phy_flags & BNX_PHY_INT_MODE_AUTO_POLLING_FLAG) { val1 = REG_RD(sc, BNX_EMAC_MDIO_MODE); val1 &= ~BNX_EMAC_MDIO_MODE_AUTO_POLL; @@ -2179,6 +2204,7 @@ bnx_get_media(struct bnx_softc *sc) DBPRINT(sc, BNX_INFO_LOAD, "BCM5709 s/w configured for SerDes.\n"); sc->bnx_phy_flags |= BNX_PHY_SERDES_FLAG; + break; default: DBPRINT(sc, BNX_INFO_LOAD, "BCM5709 s/w configured for Copper.\n"); @@ -2191,6 +2217,7 @@ bnx_get_media(struct bnx_softc *sc) DBPRINT(sc, BNX_INFO_LOAD, "BCM5709 s/w configured for SerDes.\n"); sc->bnx_phy_flags |= BNX_PHY_SERDES_FLAG; + break; default: DBPRINT(sc, BNX_INFO_LOAD, "BCM5709 s/w configured for Copper.\n"); @@ -2202,6 +2229,14 @@ bnx_get_media(struct bnx_softc *sc) if (sc->bnx_phy_flags && BNX_PHY_SERDES_FLAG) { sc->bnx_flags |= BNX_NO_WOL_FLAG; + + if (BNX_CHIP_NUM(sc) == BNX_CHIP_NUM_5709) + sc->bnx_phy_flags |= BNX_PHY_IEEE_CLAUSE_45_FLAG; + + /* + * The BCM5708S, BCM5709S, and BCM5716S controllers use a + * separate PHY for SerDes. + */ if (BNX_CHIP_NUM(sc) != BNX_CHIP_NUM_5706) { sc->bnx_phy_addr = 2; val = REG_RD_IND(sc, sc->bnx_shmem_base + @@ -2222,6 +2257,36 @@ bnx_get_media_exit: } /****************************************************************************/ +/* Performs PHY initialization required before MII drivers access the */ +/* device. */ +/* */ +/* Returns: */ +/* Nothing. */ +/****************************************************************************/ +void +bnx_init_media(struct bnx_softc *sc) +{ + if (sc->bnx_phy_flags & BNX_PHY_IEEE_CLAUSE_45_FLAG) { + /* + * Configure the BCM5709S / BCM5716S PHYs to use traditional + * IEEE Clause 22 method. Otherwise we have no way to attach + * the PHY to the mii(4) layer. PHY specific configuration + * is done by the mii(4) layer. + */ + + /* Select auto-negotiation MMD of the PHY. */ + bnx_miibus_write_reg(&sc->bnx_dev, sc->bnx_phy_addr, + BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_ADDR_EXT); + + bnx_miibus_write_reg(&sc->bnx_dev, sc->bnx_phy_addr, + BRGPHY_ADDR_EXT, BRGPHY_ADDR_EXT_AN_MMD); + + bnx_miibus_write_reg(&sc->bnx_dev, sc->bnx_phy_addr, + BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_COMBO_IEEE0); + } +} + +/****************************************************************************/ /* Free any DMA memory owned by the driver. */ /* */ /* Scans through each data structre that requires DMA memory and frees */ diff --git a/sys/dev/pci/if_bnxreg.h b/sys/dev/pci/if_bnxreg.h index 6d370c9f7c1..19462818bfa 100644 --- a/sys/dev/pci/if_bnxreg.h +++ b/sys/dev/pci/if_bnxreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bnxreg.h,v 1.34 2009/11/23 10:54:43 claudio Exp $ */ +/* $OpenBSD: if_bnxreg.h,v 1.35 2010/05/24 21:23:23 sthen Exp $ */ /*- * Copyright (c) 2006 Broadcom Corporation @@ -4803,6 +4803,7 @@ struct bnx_softc { #define BNX_PHY_INT_MODE_MASK_FLAG 0x300 #define BNX_PHY_INT_MODE_AUTO_POLLING_FLAG 0x100 #define BNX_PHY_INT_MODE_LINK_READY_FLAG 0x200 +#define BNX_PHY_IEEE_CLAUSE_45_FLAG 0x400 /* Values that need to be shared with the PHY driver. */ u_int32_t bnx_shared_hw_cfg; |