summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2010-05-24 21:23:24 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2010-05-24 21:23:24 +0000
commit7981d0a60d42ce13b2507f247abee1bccefd09b0 (patch)
tree2390d982d5bb12d48ec02de9be36411416a9288e /sys/dev
parentadc81c591b6b23e6d9bd665eb81f389471e1b040 (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.c119
-rw-r--r--sys/dev/mii/brgphyreg.h57
-rw-r--r--sys/dev/pci/if_bnx.c69
-rw-r--r--sys/dev/pci/if_bnxreg.h3
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;