summaryrefslogtreecommitdiff
path: root/sys/dev/mii
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2008-09-26 10:35:16 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2008-09-26 10:35:16 +0000
commit17fa253b80cce2fd92c8f1af0f69aff3ee1eadd7 (patch)
tree40490af44b8a4f9e7beb12df07d6a67a20922a44 /sys/dev/mii
parent3cfa51bd587e168a001ea6c5e1d0cfb55710cd87 (diff)
Add drivers for the JMicron JMC250/JMC260 Ethernet controllers
and JMicron JMP202/JMP211 Ethernet PHYs. Written by Pyun YongHyeon for FreeBSD, ported to DragonFlyBSD by Sepherosa Ziehau and then ported to OpenBSD by me. Thanks once again to JMicron for supplying hardware and information which made this possible. Some cleanup still needs to be done, and checksum offload needs to be sorted out, but the driver otherwise seems to work great. Comitted over a JMC250 card.
Diffstat (limited to 'sys/dev/mii')
-rw-r--r--sys/dev/mii/files.mii6
-rw-r--r--sys/dev/mii/jmphy.c356
-rw-r--r--sys/dev/mii/jmphyreg.h115
3 files changed, 476 insertions, 1 deletions
diff --git a/sys/dev/mii/files.mii b/sys/dev/mii/files.mii
index 87b67536c9d..866728f4b3e 100644
--- a/sys/dev/mii/files.mii
+++ b/sys/dev/mii/files.mii
@@ -1,4 +1,4 @@
-# $OpenBSD: files.mii,v 1.28 2008/09/25 20:47:16 brad Exp $
+# $OpenBSD: files.mii,v 1.29 2008/09/26 10:35:15 jsg Exp $
# $NetBSD: files.mii,v 1.13 1998/11/05 00:36:48 thorpej Exp $
file dev/mii/mii.c mii
@@ -129,6 +129,10 @@ device etphy: mii_phy
attach etphy at mii
file dev/mii/etphy.c etphy
+device jmphy: mii_phy
+attach jmphy at mii
+file dev/mii/jmphy.c jmphy
+
device atphy: mii_phy
attach atphy at mii
file dev/mii/atphy.c atphy
diff --git a/sys/dev/mii/jmphy.c b/sys/dev/mii/jmphy.c
new file mode 100644
index 00000000000..261106d64bf
--- /dev/null
+++ b/sys/dev/mii/jmphy.c
@@ -0,0 +1,356 @@
+/* $OpenBSD: jmphy.c,v 1.1 2008/09/26 10:35:15 jsg Exp $ */
+/*-
+ * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/mii/jmphy.c,v 1.1 2008/05/27 01:16:40 yongari Exp $
+ * $DragonFly: src/sys/dev/netif/mii_layer/jmphy.c,v 1.1 2008/07/22 11:28:49 sephe Exp $
+ */
+
+/*
+ * Driver for the JMicron JMP211 10/100/1000, JMP202 10/100 PHY.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+#include <dev/mii/jmphyreg.h>
+
+int jmphy_service(struct mii_softc *, struct mii_data *, int);
+void jmphy_status(struct mii_softc *);
+int jmphy_match(struct device *, void *, void *);
+void jmphy_attach(struct device *, struct device *, void *);
+void jmphy_reset(struct mii_softc *);
+uint16_t jmphy_anar(struct ifmedia_entry *);
+int jmphy_auto(struct mii_softc *, struct ifmedia_entry *);
+
+const struct mii_phy_funcs jmphy_funcs = {
+ jmphy_service, jmphy_status, jmphy_reset,
+};
+
+struct cfattach jmphy_ca = {
+ sizeof (struct mii_softc), jmphy_match, jmphy_attach,
+ mii_phy_detach, mii_phy_activate
+};
+
+struct cfdriver jmphy_cd = {
+ NULL, "jmphy", DV_DULL
+};
+
+static const struct mii_phydesc jmphys[] = {
+ { MII_OUI_JMICRON, MII_MODEL_JMICRON_JMP202,
+ MII_STR_JMICRON_JMP202 },
+ { MII_OUI_JMICRON, MII_MODEL_JMICRON_JMP211,
+ MII_STR_JMICRON_JMP211 },
+ { 0, 0,
+ NULL },
+};
+
+int
+jmphy_match(struct device *parent, void *match, void *aux)
+{
+ struct mii_attach_args *ma = aux;
+
+ if (mii_phy_match(ma, jmphys) != NULL)
+ return (10);
+
+ return (0);
+}
+
+void
+jmphy_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct mii_softc *sc = (struct mii_softc *)self;
+ struct mii_attach_args *ma = aux;
+ struct mii_data *mii = ma->mii_data;
+ const struct mii_phydesc *mpd;
+
+ mpd = mii_phy_match(ma, jmphys);
+ printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
+
+ sc->mii_inst = mii->mii_instance;
+ sc->mii_phy = ma->mii_phyno;
+ sc->mii_funcs = &jmphy_funcs;
+ sc->mii_model = MII_MODEL(ma->mii_id2);
+ sc->mii_pdata = mii;
+ sc->mii_flags = ma->mii_flags;
+
+ sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
+
+ jmphy_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);
+
+ if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
+ (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
+ ;
+ else
+ mii_phy_add_media(sc);
+}
+
+int
+jmphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
+{
+ struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
+ uint16_t bmcr;
+
+ 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;
+
+ if (jmphy_auto(sc, ife) != EJUSTRETURN)
+ 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 for link. */
+ if (PHY_READ(sc, JMPHY_SSR) & JMPHY_SSR_LINK_UP) {
+ 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)
+ return (0);
+
+ sc->mii_ticks = 0;
+ jmphy_auto(sc, ife);
+ break;
+ }
+
+ /* Update the media status. */
+ jmphy_status(sc);
+
+ /* Callback if something changed. */
+ mii_phy_update(sc, cmd);
+ return (0);
+}
+
+void
+jmphy_status(struct mii_softc *sc)
+{
+ struct mii_data *mii = sc->mii_pdata;
+ int bmcr, ssr;
+
+ mii->mii_media_status = IFM_AVALID;
+ mii->mii_media_active = IFM_ETHER;
+
+ ssr = PHY_READ(sc, JMPHY_SSR);
+ if ((ssr & JMPHY_SSR_LINK_UP) != 0)
+ mii->mii_media_status |= IFM_ACTIVE;
+
+ bmcr = PHY_READ(sc, MII_BMCR);
+ if ((bmcr & BMCR_ISO) != 0) {
+ mii->mii_media_active |= IFM_NONE;
+ mii->mii_media_status = 0;
+ return;
+ }
+
+ if ((bmcr & BMCR_LOOP) != 0)
+ mii->mii_media_active |= IFM_LOOP;
+
+ if ((ssr & JMPHY_SSR_SPD_DPLX_RESOLVED) == 0) {
+ /* Erg, still trying, I guess... */
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ switch ((ssr & JMPHY_SSR_SPEED_MASK)) {
+ case JMPHY_SSR_SPEED_1000:
+ mii->mii_media_active |= IFM_1000_T;
+ /*
+ * jmphy(4) got a valid link so reset mii_ticks.
+ * Resetting mii_ticks is needed in order to
+ * detect link loss after auto-negotiation.
+ */
+ sc->mii_ticks = 0;
+ break;
+ case JMPHY_SSR_SPEED_100:
+ mii->mii_media_active |= IFM_100_TX;
+ sc->mii_ticks = 0;
+ break;
+ case JMPHY_SSR_SPEED_10:
+ mii->mii_media_active |= IFM_10_T;
+ sc->mii_ticks = 0;
+ break;
+ default:
+ mii->mii_media_active |= IFM_NONE;
+ return;
+ }
+
+ if ((ssr & JMPHY_SSR_DUPLEX) != 0)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+ /* XXX Flow-control. */
+#ifdef notyet
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
+ if ((PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0)
+ mii->mii_media_active |= IFM_ETH_MASTER;
+ }
+#endif
+}
+
+void
+jmphy_reset(struct mii_softc *sc)
+{
+ int i;
+
+ /* Disable sleep mode. */
+ PHY_WRITE(sc, JMPHY_TMCTL,
+ PHY_READ(sc, JMPHY_TMCTL) & ~JMPHY_TMCTL_SLEEP_ENB);
+ PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN);
+
+ for (i = 0; i < 1000; i++) {
+ DELAY(1);
+ if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0)
+ break;
+ }
+}
+
+uint16_t
+jmphy_anar(struct ifmedia_entry *ife)
+{
+ uint16_t anar;
+
+ anar = 0;
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
+ break;
+ case IFM_1000_T:
+ break;
+ case IFM_100_TX:
+ anar |= ANAR_TX | ANAR_TX_FD;
+ break;
+ case IFM_10_T:
+ anar |= ANAR_10 | ANAR_10_FD;
+ break;
+ default:
+ break;
+ }
+
+ return (anar);
+}
+
+int
+jmphy_auto(struct mii_softc *sc, struct ifmedia_entry *ife)
+{
+ uint16_t anar, bmcr, gig;
+
+ gig = 0;
+ bmcr = PHY_READ(sc, MII_BMCR);
+ switch (IFM_SUBTYPE(ife->ifm_media)) {
+ case IFM_AUTO:
+ gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
+ break;
+ case IFM_1000_T:
+ gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
+ break;
+ case IFM_100_TX:
+ case IFM_10_T:
+ break;
+ case IFM_NONE:
+ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO | BMCR_PDOWN);
+ return (EJUSTRETURN);
+ default:
+ return (EINVAL);
+ }
+
+ if ((ife->ifm_media & IFM_LOOP) != 0)
+ bmcr |= BMCR_LOOP;
+
+ anar = jmphy_anar(ife);
+ /* XXX Always advertise pause capability. */
+ anar |= (3 << 10);
+
+ if ((sc->mii_flags & MIIF_HAVE_GTCR) != 0) {
+#ifdef notyet
+ struct mii_data *mii;
+
+ mii = sc->mii_pdata;
+ if ((mii->mii_media.ifm_media & IFM_ETH_MASTER) != 0)
+ gig |= GTCR_MAN_MS | GTCR_MAN_ADV;
+#endif
+ PHY_WRITE(sc, MII_100T2CR, gig);
+ }
+ PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA);
+ PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_AUTOEN | BMCR_STARTNEG);
+
+ return (EJUSTRETURN);
+}
diff --git a/sys/dev/mii/jmphyreg.h b/sys/dev/mii/jmphyreg.h
new file mode 100644
index 00000000000..d8f58366f25
--- /dev/null
+++ b/sys/dev/mii/jmphyreg.h
@@ -0,0 +1,115 @@
+/* $OpenBSD: jmphyreg.h,v 1.1 2008/09/26 10:35:15 jsg Exp $ */
+/*-
+ * Copyright (c) 2008, Pyun YongHyeon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/mii/jmphyreg.h,v 1.1 2008/05/27 01:16:40 yongari Exp $
+ * $DragonFly: src/sys/dev/netif/mii_layer/jmphyreg.h,v 1.2 2008/09/13 04:04:39 sephe Exp $
+ */
+
+#ifndef _DEV_MII_JMPHYREG_H_
+#define _DEV_MII_JMPHYREG_H_
+
+/*
+ * Registers for the JMicron JMC250 Gigabit PHY.
+ */
+
+/* PHY specific status register. */
+#define JMPHY_SSR 0x11
+#define JMPHY_SSR_SPEED_1000 0x8000
+#define JMPHY_SSR_SPEED_100 0x4000
+#define JMPHY_SSR_SPEED_10 0x0000
+#define JMPHY_SSR_SPEED_MASK 0xC000
+#define JMPHY_SSR_DUPLEX 0x2000
+#define JMPHY_SSR_SPD_DPLX_RESOLVED 0x0800
+#define JMPHY_SSR_LINK_UP 0x0400
+#define JMPHY_SSR_MDI_XOVER 0x0040
+#define JMPHY_SSR_INV_POLARITY 0x0002
+
+/* PHY specific cable length status register. */
+#define JMPHY_SCL 0x17
+#define JMPHY_SCL_CHAN_D_MASK 0xF000
+#define JMPHY_SCL_CHAN_C_MASK 0x0F00
+#define JMPHY_SCL_CHAN_B_MASK 0x00F0
+#define JMPHY_SCL_CHAN_A_MASK 0x000F
+#define JMPHY_SCL_LEN_35 0
+#define JMPHY_SCL_LEN_40 1
+#define JMPHY_SCL_LEN_50 2
+#define JMPHY_SCL_LEN_60 3
+#define JMPHY_SCL_LEN_70 4
+#define JMPHY_SCL_LEN_80 5
+#define JMPHY_SCL_LEN_90 6
+#define JMPHY_SCL_LEN_100 7
+#define JMPHY_SCL_LEN_110 8
+#define JMPHY_SCL_LEN_120 9
+#define JMPHY_SCL_LEN_130 10
+#define JMPHY_SCL_LEN_140 11
+#define JMPHY_SCL_LEN_150 12
+#define JMPHY_SCL_LEN_160 13
+#define JMPHY_SCL_LEN_170 14
+#define JMPHY_SCL_RSVD 15
+
+/* PHY specific LED control register 1. */
+#define JMPHY_LED_CTL1 0x18
+#define JMPHY_LED_BLINK_42MS 0x0000
+#define JMPHY_LED_BLINK_84MS 0x2000
+#define JMPHY_LED_BLINK_170MS 0x4000
+#define JMPHY_LED_BLINK_340MS 0x6000
+#define JMPHY_LED_BLINK_670MS 0x8000
+#define JMPHY_LED_BLINK_MASK 0xE000
+#define JMPHY_LED_FLP_GAP_MASK 0x1F00
+#define JMPHY_LED_FLP_GAP_DEFULT 0x1000
+#define JMPHY_LED2_POLARITY_MASK 0x0030
+#define JMPHY_LED1_POLARITY_MASK 0x000C
+#define JMPHY_LED0_POLARITY_MASK 0x0003
+#define JMPHY_LED_ON_LO_OFF_HI 0
+#define JMPHY_LED_ON_HI_OFF_HI 1
+#define JMPHY_LED_ON_LO_OFF_TS 2
+#define JMPHY_LED_ON_HI_OFF_TS 3
+
+/* PHY specific LED control register 2. */
+#define JMPHY_LED_CTL2 0x19
+#define JMPHY_LED_NO_STRETCH 0x0000
+#define JMPHY_LED_STRETCH_42MS 0x2000
+#define JMPHY_LED_STRETCH_84MS 0x4000
+#define JMPHY_LED_STRETCH_170MS 0x6000
+#define JMPHY_LED_STRETCH_340MS 0x8000
+#define JMPHY_LED_STRETCH_670MS 0xB000
+#define JMPHY_LED_STRETCH_1300MS 0xC000
+#define JMPHY_LED_STRETCH_2700MS 0xE000
+#define JMPHY_LED2_MODE_MASK 0x0F00
+#define JMPHY_LED1_MODE_MASK 0x00F0
+#define JMPHY_LED0_MODE_MASK 0x000F
+
+/* PHY specific test mode control register. */
+#define JMPHY_TMCTL 0x1A
+#define JMPHY_TMCTL_SLEEP_ENB 0x1000
+
+/* PHY specific configuration */
+#define JMPHY_CONF 0x1B
+#define JMPHY_CONF_EXTFIFO 0x0000 /* use extended fifo */
+#define JMPHY_CONF_DEFFIFO 0x0004 /* use default fifo */
+
+#endif /* _DEV_MII_JMPHYREG_H_ */