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