Module Name:    src
Committed By:   msaitoh
Date:           Wed Nov  6 16:02:53 UTC 2019

Modified Files:
        src/share/man/man4: micphy.4
        src/sys/dev/mii: micphy.c

Log Message:
 Add support for KSZ80[0456]1, KSZ8721, KSZ9[01]31, KS8731 and KSZ9477.
It also supports LAN7430's internal PHY. First wrote by nisimura@ and added
some device support by me. Not tested well.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/share/man/man4/micphy.4
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/mii/micphy.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/micphy.4
diff -u src/share/man/man4/micphy.4:1.2 src/share/man/man4/micphy.4:1.3
--- src/share/man/man4/micphy.4:1.2	Mon Mar  3 09:10:46 2014
+++ src/share/man/man4/micphy.4	Wed Nov  6 16:02:53 2019
@@ -1,4 +1,4 @@
-.\"	$NetBSD: micphy.4,v 1.2 2014/03/03 09:10:46 wiz Exp $
+.\"	$NetBSD: micphy.4,v 1.3 2019/11/06 16:02:53 msaitoh Exp $
 .\"
 .\" Copyright (c) 2014 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -15,18 +15,20 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd March 3, 2014
+.Dd November 6, 2019
 .Dt MICPHY 4
 .Os
 .Sh NAME
 .Nm micphy
-.Nd Micrel KSZ9021 10/100/1000 PHY driver
+.Nd Micrel KSZ8xxx 10/100 and KSZ9xxx 10/100/1000 PHY driver
 .Sh SYNOPSIS
 .Cd "micphy* at mii? phy ?"
 .Sh DESCRIPTION
 The
 .Nm
-driver currently supports only Micrel KSZ9021RN PHY.
+driver currently supports KSZ80[2345689]1, KSZ87[23]x, KSZ90[23]1, KSZ9131 and
+KSZ9477.
+It also supports LAN7430's internal PHY.
 The driver has a fixup for
 .Xr evbarm/cpsw 4
 which requires Gig-E PHYs to adjust RGMII signal timing.

Index: src/sys/dev/mii/micphy.c
diff -u src/sys/dev/mii/micphy.c:1.8 src/sys/dev/mii/micphy.c:1.9
--- src/sys/dev/mii/micphy.c:1.8	Mon Mar 25 07:34:13 2019
+++ src/sys/dev/mii/micphy.c	Wed Nov  6 16:02:53 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: micphy.c,v 1.8 2019/03/25 07:34:13 msaitoh Exp $	*/
+/*	$NetBSD: micphy.c,v 1.9 2019/11/06 16:02:53 msaitoh Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
@@ -55,11 +55,11 @@
  */
 
 /*
- * Driver for Micrel KSZ9021RN PHYs
+ * Driver for Micrel KSZ8xxx 10/100 and KSZ9xxx 10/100/1000 PHY.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: micphy.c,v 1.8 2019/03/25 07:34:13 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: micphy.c,v 1.9 2019/11/06 16:02:53 msaitoh Exp $");
 
 #include "opt_mii.h"
 
@@ -87,19 +87,98 @@ CFATTACH_DECL3_NEW(micphy, sizeof(struct
     DVF_DETACH_SHUTDOWN);
 
 static int	micphy_service(struct mii_softc *, struct mii_data *, int);
+static void	micphy_status(struct mii_softc *);
 static void	micphy_fixup(struct mii_softc *, int, int, device_t);
 
 static const struct mii_phy_funcs micphy_funcs = {
-	micphy_service, ukphy_status, micphy_reset,
+	micphy_service, micphy_status, micphy_reset,
+};
+
+struct micphy_softc {
+	struct mii_softc sc_mii;
+	uint32_t sc_lstype;	/* Type of link status register */
 };
 
 static const struct mii_phydesc micphys[] = {
-	MII_PHY_DESC(MICREL, KSZ8081),
-	MII_PHY_DESC(MICREL, KSZ9021RNI),
+	MII_PHY_DESC(MICREL, KSZ8041),
+	MII_PHY_DESC(MICREL, KSZ8051), /* +8021,8031 */
+	MII_PHY_DESC(MICREL, KSZ8061),
+	MII_PHY_DESC(MICREL, KSZ8081), /* +8051,8091 */
+	MII_PHY_DESC(MICREL, KS8737),
+	MII_PHY_DESC(MICREL, KSZ9021_8001_8721),
+	MII_PHY_DESC(MICREL, KSZ9031),
+	MII_PHY_DESC(MICREL, KSZ9131),
+	MII_PHY_DESC(MICREL, KSZ9477), /* +LAN7430internal */
 	MII_PHY_END,
 };
 
-#define	MII_KSZ8081_PHYCTL2			0x1f
+/*
+ * Model Rev. Media  LSTYPE Devices	   
+ *
+ * 0x11	      100    1F_42  KSZ8041
+ * 0x13	      100    1F_42? KSZ8041RNLI
+ * 0x15	   ?  100    1E_20  KSZ8051
+ * 	 0x5  100    1E_20  KSZ8021
+ * 	 0x6  100    1E_20  KSZ8031
+ * 0x16	   ?  100    1E_20  KSZ8081
+ * 	   ?  100    1E_20  KSZ8091
+ * 0x17	      100    1E_20  KSZ8061
+ * 0x21	 0x0  giga   GIGA   KSZ9021
+ * 	 0x1  giga   GIGA   KSZ9021RLRN
+ * 	 0x9  100    1F_42  KSZ8721BL/SL
+ * 	 0x9  100    none?  KSZ8721CL
+ * 	 0xa  100    1F_42  KSZ8001
+ * 0x22	      giga   GIGA   KSZ9031
+ * 0x23	   1? gigasw GIGA   KSZ9477 (No master/slave bit) 
+ * 	   5? giga   GIGA   LAN7430internal
+ * 0x24	      giga   GIGA   KSZ9131	   
+ * 0x32	      100    1F_42  KS8737	   
+ */
+
+/* Type of link status register */
+#define MICPHYF_LSTYPE_DEFAULT	0
+#define MICPHYF_LSTYPE_1F_42	1
+#define MICPHYF_LSTYPE_1E_20	2
+#define MICPHYF_LSTYPE_GIGA	3
+
+/* Return if the device is Gigabit (KSZ9021) */
+#define KSZ_MODEL21H_GIGA(rev)			\
+	((((rev) & 0x0e) == 0) ? true : false)
+
+#define KSZ_XREG_CONTROL	0x0b
+#define KSZ_XREG_WRITE		0x0c
+#define KSZ_XREG_READ		0x0d
+#define KSZ_XREG_CTL_SEL_READ	0x0000
+#define KSZ_XREG_CTL_SEL_WRITE	0x8000
+
+#define REG_RGMII_CLOCK_AND_CONTROL	0x104
+#define REG_RGMII_RX_DATA		0x105
+
+/* PHY control 1 register for 10/100 PHYs (KSZ80[235689]1) */
+#define KSZ8051_PHYCTL1		0x1e
+#define KSZ8051_PHY_LINK	0x0100
+#define KSZ8051_PHY_MDIX	0x0020
+#define KSZ8051_PHY_FDX		0x0004
+#define KSZ8051_PHY_SPD_MASK	0x0003
+#define KSZ8051_PHY_SPD_10T	0x0001
+#define KSZ8051_PHY_SPD_100TX	0x0002
+
+/* PHY control 2 register for 10/100 PHYs (KSZ8041, KSZ8721 and KSZ8001) */
+#define	KSZ8041_PHYCTL2		0x1f
+#define KSZ8041_PHY_ACOMP	0x0080
+#define KSZ8041_PHY_SPD_MASK	0x001c
+#define KSZ8041_PHY_SPD_10T	0x0004
+#define KSZ8041_PHY_SPD_100TX	0x0008
+#define KSZ8041_PHY_FDX		0x0010
+#define KSZ8051_PHYCTL2		0x1f
+
+/* PHY control register for Gigabit PHYs */
+#define KSZ_GPHYCTL		0x1f
+#define KSZ_GPHY_SPD_1000T	0x0040
+#define KSZ_GPHY_SPD_100TX	0x0020
+#define KSZ_GPHY_SPD_10T	0x0010
+#define KSZ_GPHY_FDX		0x0008
+#define KSZ_GPHY_1000T_MS	0x0004
 
 static int
 micphymatch(device_t parent, cfdata_t match, void *aux)
@@ -115,7 +194,8 @@ micphymatch(device_t parent, cfdata_t ma
 static void
 micphyattach(device_t parent, device_t self, void *aux)
 {
-	struct mii_softc *sc = device_private(self);
+	struct micphy_softc *msc = device_private(self);
+	struct mii_softc *sc = &msc->sc_mii;
 	struct mii_attach_args *ma = aux;
 	struct mii_data *mii = ma->mii_data;
 	int model = MII_MODEL(ma->mii_id2);
@@ -134,6 +214,25 @@ micphyattach(device_t parent, device_t s
 	sc->mii_flags = ma->mii_flags;
 	sc->mii_anegticks = MII_ANEGTICKS;
 
+	if ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8041)
+	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8041RNLI)
+	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KS8737)
+	    || ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9021_8001_8721)
+		&& !KSZ_MODEL21H_GIGA(sc->mii_mpd_rev))) {
+		msc->sc_lstype = MICPHYF_LSTYPE_1F_42;
+	} else if ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8051)
+	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
+	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8061)) {
+		msc->sc_lstype = MICPHYF_LSTYPE_1E_20;
+	} else if (((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9021_8001_8721)
+		&& KSZ_MODEL21H_GIGA(sc->mii_mpd_rev))
+	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9031)
+	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9477)
+	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9131)) {
+		msc->sc_lstype = MICPHYF_LSTYPE_GIGA;
+	} else
+		msc->sc_lstype = MICPHYF_LSTYPE_DEFAULT;
+
 	PHY_RESET(sc);
 
 	micphy_fixup(sc, model, rev, parent);
@@ -164,10 +263,10 @@ micphy_reset(struct mii_softc *sc)
 	 * behavior).
 	 */
 	if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
-		PHY_READ(sc, MII_KSZ8081_PHYCTL2, &reg);
+		PHY_READ(sc, KSZ8051_PHYCTL2, &reg);
 	mii_phy_reset(sc);
 	if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
-		PHY_WRITE(sc, MII_KSZ8081_PHYCTL2, reg);
+		PHY_WRITE(sc, KSZ8051_PHYCTL2, reg);
 }
 
 static int
@@ -223,24 +322,15 @@ micphy_service(struct mii_softc *sc, str
 	return 0;
 }
 
-#define XREG_CONTROL	0x0b
-#define XREG_WRITE	0x0c
-#define XREG_READ	0x0d
-#define XREG_CTL_SEL_READ	0x0000
-#define XREG_CTL_SEL_WRITE	0x8000
-
-#define REG_RGMII_CLOCK_AND_CONTROL	0x104
-#define REG_RGMII_RX_DATA		0x105
-
 static void
 micphy_writexreg(struct mii_softc *sc, uint32_t reg, uint32_t wval)
 {
 	uint16_t rval __debugused;
 
-	PHY_WRITE(sc, XREG_CONTROL, XREG_CTL_SEL_WRITE | reg);
-	PHY_WRITE(sc, XREG_WRITE, wval);
-	PHY_WRITE(sc, XREG_CONTROL, XREG_CTL_SEL_READ | reg);
-	PHY_READ(sc, XREG_READ, &rval);
+	PHY_WRITE(sc, KSZ_XREG_CONTROL, KSZ_XREG_CTL_SEL_WRITE | reg);
+	PHY_WRITE(sc, KSZ_XREG_WRITE, wval);
+	PHY_WRITE(sc, KSZ_XREG_CONTROL, KSZ_XREG_CTL_SEL_READ | reg);
+	PHY_READ(sc, KSZ_XREG_READ, &rval);
 	KDASSERT(wval == rval);
 }
 
@@ -248,7 +338,7 @@ static void
 micphy_fixup(struct mii_softc *sc, int model, int rev, device_t parent)
 {
 	switch (model) {
-	case MII_MODEL_MICREL_KSZ9021RNI:
+	case MII_MODEL_MICREL_KSZ9021_8001_8721:
 		if (!device_is_a(parent, "cpsw"))
 			break;
 
@@ -268,3 +358,77 @@ micphy_fixup(struct mii_softc *sc, int m
 
 	return;
 }
+
+static void
+micphy_status(struct mii_softc *sc)
+{
+	struct micphy_softc *msc = device_private(sc->mii_dev);
+	struct mii_data *mii = sc->mii_pdata;
+	uint16_t bmsr, bmcr, sr;
+
+	/* For unknown devices */
+	if (msc->sc_lstype == MICPHYF_LSTYPE_DEFAULT) {
+		ukphy_status(sc);
+		return;
+	}
+
+	mii->mii_media_status = IFM_AVALID;
+	mii->mii_media_active = IFM_ETHER;
+
+	PHY_READ(sc, MII_BMCR, &bmcr);
+
+	PHY_READ(sc, MII_BMSR, &bmsr);
+	PHY_READ(sc, MII_BMSR, &bmsr);
+	if (bmsr & BMSR_LINK)
+		mii->mii_media_status |= IFM_ACTIVE;
+
+	if (bmcr & BMCR_AUTOEN) {
+		if ((bmsr & BMSR_ACOMP) == 0) {
+			mii->mii_media_active |= IFM_NONE;
+			return;
+		}
+	}
+
+	if (msc->sc_lstype == MICPHYF_LSTYPE_1F_42) {
+		PHY_READ(sc, KSZ8041_PHYCTL2, &sr);
+		if ((sr & KSZ8041_PHY_SPD_MASK) == 0)
+			mii->mii_media_active |= IFM_NONE;
+		else if (sr & KSZ8041_PHY_SPD_100TX)
+			mii->mii_media_active |= IFM_100_TX;
+		else if (sr & KSZ8041_PHY_SPD_10T)
+			mii->mii_media_active |= IFM_10_T;
+		if (sr & KSZ8041_PHY_FDX)
+			mii->mii_media_active |= IFM_FDX
+			    | mii_phy_flowstatus(sc);
+	} else if (msc->sc_lstype == MICPHYF_LSTYPE_1E_20) {
+		PHY_READ(sc, KSZ8051_PHYCTL1, &sr);
+		if ((sr & KSZ8051_PHY_SPD_MASK) == 0)
+			mii->mii_media_active |= IFM_NONE;
+		else if (sr & KSZ8051_PHY_SPD_100TX)
+			mii->mii_media_active |= IFM_100_TX;
+		else if (sr & KSZ8051_PHY_SPD_10T)
+			mii->mii_media_active |= IFM_10_T;
+		if (sr & KSZ8051_PHY_FDX)
+			mii->mii_media_active |= IFM_FDX
+			    | mii_phy_flowstatus(sc);
+	} else if (msc->sc_lstype == MICPHYF_LSTYPE_GIGA) {
+		/* 9021/9031/7430/9131 gphy */
+		PHY_READ(sc, KSZ_GPHYCTL, &sr);
+		if (sr & KSZ_GPHY_SPD_1000T)
+			mii->mii_media_active |= IFM_1000_T;
+		else if (sr & KSZ_GPHY_SPD_100TX)
+			mii->mii_media_active |= IFM_100_TX;
+		else if (sr & KSZ_GPHY_SPD_10T)
+			mii->mii_media_active |= IFM_10_T;
+		else
+			mii->mii_media_active |= IFM_NONE;
+		if ((mii->mii_media_active & IFM_1000_T)
+		    && (sr & KSZ_GPHY_1000T_MS))
+			mii->mii_media_active |= IFM_ETH_MASTER;
+		if (sr & KSZ_GPHY_FDX)
+			mii->mii_media_active |= IFM_FDX
+			    | mii_phy_flowstatus(sc);
+		else
+			mii->mii_media_active |= IFM_HDX;
+	}
+}

Reply via email to