Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/usb Add GPIO programming to support more PHY.
details: https://anonhg.NetBSD.org/src/rev/4e35746f7474
branches: trunk
changeset: 791208:4e35746f7474
user: roy <roy%NetBSD.org@localhost>
date: Fri Nov 08 17:46:35 2013 +0000
description:
Add GPIO programming to support more PHY.
Most of the work done by skrll@ taken from FreeBSD,
but finished and tested by me using an AX88178 axe and a RTL8211 PHY.
diffstat:
sys/dev/usb/if_axe.c | 260 ++++++++++++++++++++++++++++++++++-------------
sys/dev/usb/if_axereg.h | 40 +++++++-
2 files changed, 225 insertions(+), 75 deletions(-)
diffs (truncated from 437 to 300 lines):
diff -r e01a62b63991 -r 4e35746f7474 sys/dev/usb/if_axe.c
--- a/sys/dev/usb/if_axe.c Fri Nov 08 15:44:26 2013 +0000
+++ b/sys/dev/usb/if_axe.c Fri Nov 08 17:46:35 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_axe.c,v 1.65 2013/09/12 21:03:11 martin Exp $ */
+/* $NetBSD: if_axe.c,v 1.66 2013/11/08 17:46:35 roy Exp $ */
/* $OpenBSD: if_axe.c,v 1.96 2010/01/09 05:33:08 jsg Exp $ */
/*
@@ -89,7 +89,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.65 2013/09/12 21:03:11 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.66 2013/11/08 17:46:35 roy Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -195,7 +195,9 @@
static int axe_init(struct ifnet *);
static void axe_stop(struct ifnet *, int);
static void axe_watchdog(struct ifnet *);
+static int axe_miibus_readreg_locked(device_t, int, int);
static int axe_miibus_readreg(device_t, int, int);
+static void axe_miibus_writereg_locked(device_t, int, int, int);
static void axe_miibus_writereg(device_t, int, int, int);
static void axe_miibus_statchg(struct ifnet *);
static int axe_cmd(struct axe_softc *, int, int, int, void *);
@@ -258,70 +260,89 @@
}
static int
-axe_miibus_readreg(device_t dev, int phy, int reg)
+axe_miibus_readreg_locked(device_t dev, int phy, int reg)
{
struct axe_softc *sc = device_private(dev);
usbd_status err;
uint16_t val;
- if (sc->axe_dying) {
- DPRINTF(("axe: dying\n"));
- return 0;
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
+ err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, (void *)&val);
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
+ if (err) {
+ aprint_error_dev(sc->axe_dev, "read PHY failed\n");
+ return -1;
+ }
+
+ val = le16toh(val);
+ if (sc->axe_flags & AX772 && reg == MII_BMSR) {
+ /*
+ * BMSR of AX88772 indicates it supports extended
+ * capability but the extended status register is
+ * reserverd for embedded ethernet PHY. So clear the
+ * extended capability bit of BMSR.
+ */
+ val &= ~BMSR_EXTCAP;
}
- /*
- * The chip tells us the MII address of any supported
- * PHYs attached to the chip, so only read from those.
- *
- * But if the chip lies about its PHYs, read from any.
- */
- val = 0;
+ DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
+ phy, reg, val));
+
+ return val;
+}
+
+static int
+axe_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct axe_softc *sc = device_private(dev);
+ int val;
+
+ if (sc->axe_dying)
+ return 0;
+
+ if (sc->axe_phyno != phy)
+ return 0;
- if ((phy == sc->axe_phyaddrs[0]) || (phy == sc->axe_phyaddrs[1]) ||
- (sc->axe_flags & AXE_ANY_PHY)) {
- axe_lock_mii(sc);
- axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
- err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, (void *)&val);
- axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
- axe_unlock_mii(sc);
+ axe_lock_mii(sc);
+ val = axe_miibus_readreg_locked(dev, phy, reg);
+ axe_unlock_mii(sc);
+
+ return val;
+}
- if (err) {
- aprint_error_dev(sc->axe_dev, "read PHY failed\n");
- return -1;
- }
- DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
- phy, reg, val));
+static void
+axe_miibus_writereg_locked(device_t dev, int phy, int reg, int aval)
+{
+ struct axe_softc *sc = device_private(dev);
+ usbd_status err;
+ uint16_t val;
+
+ val = htole16(aval);
- if (val && val != 0xffff)
- sc->axe_phyaddrs[0] = phy;
- } else {
- DPRINTF(("axe_miibus_readreg: ignore read from phy 0x%x\n",
- phy));
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
+ err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, (void *)&val);
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
+
+ if (err) {
+ aprint_error_dev(sc->axe_dev, "write PHY failed\n");
+ return;
}
- return le16toh(val);
}
static void
axe_miibus_writereg(device_t dev, int phy, int reg, int aval)
{
struct axe_softc *sc = device_private(dev);
- usbd_status err;
- uint16_t val;
if (sc->axe_dying)
return;
- val = htole16(aval);
+ if (sc->axe_phyno != phy)
+ return;
+
axe_lock_mii(sc);
- axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
- err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, (void *)&val);
- axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
+ axe_miibus_writereg_locked(dev, phy, reg, aval);
axe_unlock_mii(sc);
-
- if (err) {
- aprint_error_dev(sc->axe_dev, "write PHY failed\n");
- return;
- }
}
static void
@@ -338,7 +359,8 @@
if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
val |= (AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC);
-
+ if (sc->axe_flags & AX178)
+ val |= AXE_178_MEDIA_ENCK;
switch (IFM_SUBTYPE(mii->mii_media_active)) {
case IFM_1000_T:
val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
@@ -461,13 +483,41 @@
DELAY(1000);
}
+static int
+axe_get_phyno(struct axe_softc *sc, int sel)
+{
+ int phyno;
+
+ switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) {
+ case PHY_TYPE_100_HOME:
+ /* FALLTHROUGH */
+ case PHY_TYPE_GIG:
+ phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]);
+ break;
+ case PHY_TYPE_SPECIAL:
+ /* FALLTHROUGH */
+ case PHY_TYPE_RSVD:
+ /* FALLTHROUGH */
+ case PHY_TYPE_NON_SUP:
+ /* FALLTHROUGH */
+ default:
+ phyno = -1;
+ break;
+ }
+
+ return phyno;
+}
+
+#define AXE_GPIO_WRITE(x, y) do { \
+ axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \
+ usbd_delay_ms(sc->axe_udev, hztoms(y)); \
+} while (0)
+
static void
axe_ax88178_init(struct axe_softc *sc)
{
-#ifdef AXE_DEBUG
- int gpio0 = 0, phymode = 0;
-#endif
- uint16_t eeprom;
+ int gpio0, ledmode, phymode;
+ uint16_t eeprom, val;
axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
/* XXX magic */
@@ -479,35 +529,90 @@
DPRINTF((" EEPROM is 0x%x\n", eeprom));
/* if EEPROM is invalid we have to use to GPIO0 */
-#ifdef AXE_DEBUG
if (eeprom == 0xffff) {
- phymode = 0;
+ phymode = AXE_PHY_MODE_MARVELL;
gpio0 = 1;
+ ledmode = 0;
} else {
- phymode = eeprom & 7;
+ phymode = eeprom & 0x7f;
gpio0 = (eeprom & 0x80) ? 0 : 1;
+ ledmode = eeprom >> 8;
}
-#endif
DPRINTF(("use gpio0: %d, phymode %d\n", gpio0, phymode));
- axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL);
- usbd_delay_ms(sc->axe_udev, 40);
- if ((eeprom >> 8) != 1) {
- axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
- usbd_delay_ms(sc->axe_udev, 30);
-
- axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL);
- usbd_delay_ms(sc->axe_udev, 300);
-
- axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
- usbd_delay_ms(sc->axe_udev, 30);
- } else {
- DPRINTF(("axe gpio phymode == 1 path\n"));
- axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL);
- usbd_delay_ms(sc->axe_udev, 30);
- axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL);
- usbd_delay_ms(sc->axe_udev, 30);
+ /* Program GPIOs depending on PHY hardware. */
+ switch (phymode) {
+ case AXE_PHY_MODE_MARVELL:
+ if (gpio0 == 1) {
+ AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN,
+ hz / 32);
+ AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN,
+ hz / 32);
+ AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4);
+ AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN,
+ hz / 32);
+ } else {
+ AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 |
+ AXE_GPIO1_EN, hz / 3);
+ if (ledmode == 1) {
+ AXE_GPIO_WRITE(AXE_GPIO1_EN, hz / 3);
+ AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN,
+ hz / 3);
+ } else {
+ AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN |
+ AXE_GPIO2 | AXE_GPIO2_EN, hz / 32);
+ AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN |
+ AXE_GPIO2_EN, hz / 4);
+ AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN |
+ AXE_GPIO2 | AXE_GPIO2_EN, hz / 32);
+ }
+ }
+ break;
+ case AXE_PHY_MODE_CICADA:
+ case AXE_PHY_MODE_CICADA_V2:
+ case AXE_PHY_MODE_CICADA_V2_ASIX:
+ if (gpio0 == 1)
+ AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 |
+ AXE_GPIO0_EN, hz / 32);
+ else
+ AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 |
+ AXE_GPIO1_EN, hz / 32);
+ break;
+ case AXE_PHY_MODE_AGERE:
+ AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 |
+ AXE_GPIO1_EN, hz / 32);
+ AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 |
+ AXE_GPIO2_EN, hz / 32);
+ AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4);
+ AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 |
+ AXE_GPIO2_EN, hz / 32);
+ break;
+ case AXE_PHY_MODE_REALTEK_8211CL:
Home |
Main Index |
Thread Index |
Old Index