Add support for the Motorcomm YT8521/YT8531 PHYs. Since these PHYs may
authorkettenis <kettenis@openbsd.org>
Sat, 8 Jul 2023 08:18:30 +0000 (08:18 +0000)
committerkettenis <kettenis@openbsd.org>
Sat, 8 Jul 2023 08:18:30 +0000 (08:18 +0000)
need various board-dependent tweaks, pass the device tree node down
to the PHY driver such that we can look at various properties to make
the necessary tweaks.  Enable ytphy(4) on riscv64.

ok jsing@, patrick@

sys/arch/riscv64/conf/GENERIC
sys/arch/riscv64/conf/RAMDISK
sys/dev/fdt/if_dwqe_fdt.c
sys/dev/mii/miidevs
sys/dev/mii/miivar.h
sys/dev/mii/ytphy.c

index acf00b8..15a9abf 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: GENERIC,v 1.43 2023/07/04 13:04:08 kettenis Exp $
+#      $OpenBSD: GENERIC,v 1.44 2023/07/08 08:18:30 kettenis Exp $
 #
 # For further information on compiling OpenBSD kernels, see the config(8)
 # man page.
@@ -256,17 +256,18 @@ udl*              at uhub?                # DisplayLink USB displays
 wsdisplay*     at udl?
 bwfm*          at uhub?                # Broadcom FullMAC
 
-acphy*         at mii?         # Altima AC101 PHYs
-amphy*         at mii?         # AMD 79C873 PHYs
-atphy*         at mii?         # Attansic F1 PHYs
-bmtphy*                at mii?         # Broadcom 10/100 PHYs
-brgphy*                at mii?         # Broadcom Gigabit PHYs
-eephy*         at mii?         # Marvell 88E1000 series PHY
-rgephy*                at mii?         # Realtek 8169S/8110S PHY
-rlphy*         at mii?         # Realtek 8139 internal PHYs
-sqphy*         at mii?         # Seeq 8x220 PHYs
-ukphy*         at mii?         # "unknown" PHYs
-urlphy*                at mii?         # Realtek RTL8150L internal PHY
+acphy*         at mii?                 # Altima AC101 PHYs
+amphy*         at mii?                 # AMD 79C873 PHYs
+atphy*         at mii?                 # Attansic F1 PHYs
+bmtphy*                at mii?                 # Broadcom 10/100 PHYs
+brgphy*                at mii?                 # Broadcom Gigabit PHYs
+eephy*         at mii?                 # Marvell 88E1000 series PHY
+rgephy*                at mii?                 # Realtek 8169S/8110S PHY
+rlphy*         at mii?                 # Realtek 8139 internal PHYs
+sqphy*         at mii?                 # Seeq 8x220 PHYs
+ukphy*         at mii?                 # "unknown" PHYs
+urlphy*                at mii?                 # Realtek RTL8150L internal PHY
+ytphy*         at mii?                 # MotorComm YT8511 PHY
 
 # Pseudo-Devices
 pseudo-device  openprom
index 45bc898..955be7f 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: RAMDISK,v 1.37 2023/07/04 13:04:08 kettenis Exp $
+#      $OpenBSD: RAMDISK,v 1.38 2023/07/08 08:18:30 kettenis Exp $
 
 machine                riscv64
 maxusers       4
@@ -167,6 +167,7 @@ rlphy*              at mii?         # Realtek 8139 internal PHYs
 sqphy*         at mii?         # Seeq 8x220 PHYs
 ukphy*         at mii?         # "unknown" PHYs
 urlphy*                at mii?         # Realtek RTL8150L internal PHY
+ytphy*         at mii?         # MotorComm YT8511 PHY
 
 pseudo-device  loop 1
 pseudo-device  vlan
index 1e98c2e..af0f4e4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_dwqe_fdt.c,v 1.13 2023/07/04 12:58:42 kettenis Exp $       */
+/*     $OpenBSD: if_dwqe_fdt.c,v 1.14 2023/07/08 08:18:30 kettenis Exp $       */
 /*
  * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org>
  * Copyright (c) 2017, 2022 Patrick Wildt <patrick@blueri.se>
@@ -141,6 +141,7 @@ dwqe_fdt_attach(struct device *parent, struct device *self, void *aux)
                sc->sc_phyloc = OF_getpropint(node, "reg", MII_PHY_ANY);
        else
                sc->sc_phyloc = MII_PHY_ANY;
+       sc->sc_mii.mii_node = node;
 
        pinctrl_byname(faa->fa_node, "default");
 
index ceed41f..d68fae9 100644 (file)
@@ -1,4 +1,4 @@
-$OpenBSD: miidevs,v 1.132 2023/03/31 13:37:02 kettenis Exp $
+$OpenBSD: miidevs,v 1.133 2023/07/08 08:18:30 kettenis Exp $
 /* $NetBSD: miidevs,v 1.3 1998/11/05 03:43:43 thorpej Exp $ */
 
 /*-
@@ -72,6 +72,7 @@ oui XAQTI                     0x00e0ae        XaQti
 oui PLESSEYSEMI                        0x046b40        Plessey Semi.
 oui NATSEMI                    0x080017        National Semi.
 oui TI                         0x080028        Texas Instruments
+oui MOTORCOMM                  0x13d47a        Motorcomm
 
 /* in the 79c873, AMD uses another OUI (which matches Davicom!) */
 oui xxALTIMA                   0x000895        Altima
@@ -268,6 +269,9 @@ model MARVELL E1545         0x002a  88E1545 Quad 10/100/1000 PHY
 model MICREL KSZ9021           0x0021  KSZ9021 10/100/1000 PHY
 model MICREL KSZ9031           0x0022  KSZ9031 10/100/1000 PHY
 
+/* Motorcomm PHYs */
+model MOTORCOMM YT8531         0x0011  YT8531 10/100/1000 PHY
+
 /* Myson PHYs */
 model MYSON MTD972             0x0000  MTD972 10/100 PHY
 
index e3f5061..2349072 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: miivar.h,v 1.37 2023/04/05 10:45:07 kettenis Exp $    */
+/*     $OpenBSD: miivar.h,v 1.38 2023/07/08 08:18:30 kettenis Exp $    */
 /*     $NetBSD: miivar.h,v 1.17 2000/03/06 20:56:57 thorpej Exp $      */
 
 /*-
@@ -63,6 +63,7 @@ struct mii_data {
        struct ifnet *mii_ifp;          /* pointer back to network interface */
 
        int mii_flags;                  /* misc. flags; see below */
+       int mii_node;                   /* FDT node */
 
        /*
         * For network interfaces with multiple PHYs, a list of all
index 6e3b253..00aa82e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ytphy.c,v 1.2 2023/03/04 22:40:37 kettenis Exp $      */
+/*     $OpenBSD: ytphy.c,v 1.3 2023/07/08 08:18:30 kettenis Exp $      */
 /*
  * Copyright (c) 2001 Theo de Raadt
  * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org>
 
 #include <dev/mii/mii.h>
 #include <dev/mii/miivar.h>
+#include <dev/mii/miidevs.h>
+
+#ifdef __HAVE_FDT
+#include <machine/fdt.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
+#define MII_MODEL_MOTORCOMM_YT8511     0x10
+#define MII_MODEL_MOTORCOMM_YT8521     0x11
 
 #define YT8511_REG_ADDR                0x1e
 #define YT8511_REG_DATA                0x1f
 #define YT8511_EXT_SLEEP_CTRL          0x27
 #define  YT8511_PLL_ON_IN_SLEEP                (1 << 14)
 
+#define YT8521_EXT_CHIP_CONFIG         0xa001
+#define  YT8521_RXC_DLY_EN             (1 << 8)
+#define YT8521_EXT_RGMII_CONFIG1       0xa003
+#define  YT8521_TX_CLK_SEL             (1 << 14)
+#define  YT8521_RX_DELAY_SEL_MASK      (0xf << 10)
+#define  YT8521_RX_DELAY_SEL_SHIFT     10
+#define  YT8521_TX_DELAY_SEL_MASK      (0xf << 0)
+#define  YT8521_TX_DELAY_SEL_SHIFT     0
+
 int    ytphy_match(struct device *, void *, void *);
 void   ytphy_attach(struct device *, struct device *, void *);
 
@@ -58,22 +76,37 @@ struct cfdriver ytphy_cd = {
 };
 
 int    ytphy_service(struct mii_softc *, struct mii_data *, int);
+void   ytphy_yt8511_init(struct mii_softc *);
+void   ytphy_yt8521_init(struct mii_softc *);
+void   ytphy_yt8521_update(struct mii_softc *);
 
 const struct mii_phy_funcs ytphy_funcs = {
        ytphy_service, ukphy_status, mii_phy_reset,
 };
 
+static const struct mii_phydesc ytphys[] = {
+       { MII_OUI_MOTORCOMM,    MII_MODEL_MOTORCOMM_YT8531,
+         MII_STR_MOTORCOMM_YT8531 },
+       { 0,                    0,
+         NULL },
+};
+
 int
 ytphy_match(struct device *parent, void *match, void *aux)
 {
        struct mii_attach_args *ma = aux;
        
        /*
-        * The MotorComm YT8511 has a bogus MII OUIs, so match the
-        * complete ID including the rev.
+        * The MotorComm YT8511 and TY8521 have bogus MII OUIs, so
+        * match the complete ID including the rev.
         */
        if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x010a)
                return (10);
+       if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x011a)
+               return (10);
+
+       if (mii_phy_match(ma, ytphys) != NULL)
+               return (10);
 
        return (0);
 }
@@ -84,12 +117,16 @@ ytphy_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;
-       uint16_t tx_clk_delay_sel;
-       uint16_t rx_clk_delay_en;
-       uint16_t txc_delay_sel_fe;
-       uint16_t addr, data;
+       const struct mii_phydesc *mpd;
 
-       printf(": YT8511 10/100/1000 PHY\n");
+       mpd = mii_phy_match(ma, ytphys);
+
+       if (mpd)
+               printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
+       else if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x010a)
+               printf(": YT8511 10/100/1000 PHY\n");
+       else
+               printf(": YT8521 10/100/1000 PHY\n");
 
        sc->mii_inst = mii->mii_instance;
        sc->mii_phy = ma->mii_phyno;
@@ -99,45 +136,10 @@ ytphy_attach(struct device *parent, struct device *self, void *aux)
        sc->mii_pdata = mii;
        sc->mii_flags = ma->mii_flags;
 
-       if (ma->mii_flags & MIIF_RXID)
-               rx_clk_delay_en = YT8511_RX_CLK_DELAY_EN;
+       if (ma->mii_id1 == 0x0000 && ma->mii_id2 == 0x010a)
+               ytphy_yt8511_init(sc);
        else
-               rx_clk_delay_en = 0;
-
-       if (ma->mii_flags & MIIF_TXID) {
-               tx_clk_delay_sel = YT8511_TX_CLK_DELAY_SEL_EN;
-               txc_delay_sel_fe = YT8511_TXC_DELAY_SEL_FE_EN;
-       } else {
-               tx_clk_delay_sel = YT8511_TX_CLK_DELAY_SEL_DIS;
-               txc_delay_sel_fe = YT8511_TXC_DELAY_SEL_FE_DIS;
-       }
-
-       /* Save address register. */
-       addr = PHY_READ(sc, YT8511_REG_ADDR);
-
-       PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_CLK_GATE);
-       data = PHY_READ(sc, YT8511_REG_DATA);
-       data &= ~YT8511_TX_CLK_DELAY_SEL_MASK;
-       data &= ~YT8511_RX_CLK_DELAY_EN;
-       data &= ~YT8511_CLK_25M_SEL_MASK;
-       data |= tx_clk_delay_sel;
-       data |= rx_clk_delay_en;
-       data |= YT8511_CLK_25M_SEL_125M;
-       PHY_WRITE(sc, YT8511_REG_DATA, data);
-
-       PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_DELAY_DRIVE);
-       data = PHY_READ(sc, YT8511_REG_DATA);
-       data &= ~YT8511_TXC_DELAY_SEL_FE_MASK;
-       data |= txc_delay_sel_fe;
-       PHY_WRITE(sc, YT8511_REG_DATA, data);
-
-       PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_SLEEP_CTRL);
-       data = PHY_READ(sc, YT8511_REG_DATA);
-       data |= YT8511_PLL_ON_IN_SLEEP;
-       PHY_WRITE(sc, YT8511_REG_DATA, data);
-
-       /* Restore address register. */
-       PHY_WRITE(sc, YT8511_REG_ADDR, addr);
+               ytphy_yt8521_init(sc);
 
        sc->mii_capabilities =
            PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
@@ -208,6 +210,155 @@ ytphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
        mii_phy_status(sc);
 
        /* Callback if something changed. */
+       if (sc->mii_model != MII_MODEL_MOTORCOMM_YT8511)
+               ytphy_yt8521_update(sc);
        mii_phy_update(sc, cmd);
        return (0);
 }
+
+void
+ytphy_yt8511_init(struct mii_softc *sc)
+{
+       uint16_t tx_clk_delay_sel;
+       uint16_t rx_clk_delay_en;
+       uint16_t txc_delay_sel_fe;
+       uint16_t addr, data;
+
+       if (sc->mii_flags & MIIF_RXID)
+               rx_clk_delay_en = YT8511_RX_CLK_DELAY_EN;
+       else
+               rx_clk_delay_en = 0;
+
+       if (sc->mii_flags & MIIF_TXID) {
+               tx_clk_delay_sel = YT8511_TX_CLK_DELAY_SEL_EN;
+               txc_delay_sel_fe = YT8511_TXC_DELAY_SEL_FE_EN;
+       } else {
+               tx_clk_delay_sel = YT8511_TX_CLK_DELAY_SEL_DIS;
+               txc_delay_sel_fe = YT8511_TXC_DELAY_SEL_FE_DIS;
+       }
+
+       /* Save address register. */
+       addr = PHY_READ(sc, YT8511_REG_ADDR);
+
+       PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_CLK_GATE);
+       data = PHY_READ(sc, YT8511_REG_DATA);
+       data &= ~YT8511_TX_CLK_DELAY_SEL_MASK;
+       data &= ~YT8511_RX_CLK_DELAY_EN;
+       data &= ~YT8511_CLK_25M_SEL_MASK;
+       data |= tx_clk_delay_sel;
+       data |= rx_clk_delay_en;
+       data |= YT8511_CLK_25M_SEL_125M;
+       PHY_WRITE(sc, YT8511_REG_DATA, data);
+
+       PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_DELAY_DRIVE);
+       data = PHY_READ(sc, YT8511_REG_DATA);
+       data &= ~YT8511_TXC_DELAY_SEL_FE_MASK;
+       data |= txc_delay_sel_fe;
+       PHY_WRITE(sc, YT8511_REG_DATA, data);
+
+       PHY_WRITE(sc, YT8511_REG_ADDR, YT8511_EXT_SLEEP_CTRL);
+       data = PHY_READ(sc, YT8511_REG_DATA);
+       data |= YT8511_PLL_ON_IN_SLEEP;
+       PHY_WRITE(sc, YT8511_REG_DATA, data);
+
+       /* Restore address register. */
+       PHY_WRITE(sc, YT8511_REG_ADDR, addr);
+}
+
+void
+ytphy_yt8521_init(struct mii_softc *sc)
+{
+       uint32_t rx_delay = 1950;
+       uint32_t tx_delay = 1950;
+       int rx_delay_en = 0;
+       uint16_t addr, data;
+
+#ifdef __HAVE_FDT
+       if (sc->mii_pdata->mii_node) {
+               rx_delay = OF_getpropint(sc->mii_pdata->mii_node,
+                   "rx-internal-delay-ps", rx_delay);
+               tx_delay = OF_getpropint(sc->mii_pdata->mii_node,
+                   "tx-internal-delay-ps", tx_delay);
+       }
+#endif
+
+       /* Save address register. */
+       addr = PHY_READ(sc, YT8511_REG_ADDR);
+
+       if ((sc->mii_flags & MIIF_RXID) == 0)
+               rx_delay = 0;
+       if ((sc->mii_flags & MIIF_TXID) == 0)
+               tx_delay = 0;
+
+       if (rx_delay >= 1900 && ((rx_delay - 1900) % 150) == 0) {
+               rx_delay -= 1900;
+               rx_delay_en = 1;
+       }
+
+       PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_CHIP_CONFIG);
+       data = PHY_READ(sc, YT8511_REG_DATA);
+       if (rx_delay_en)
+               data |= YT8521_RXC_DLY_EN;
+       else
+               data &= ~YT8521_RXC_DLY_EN;
+       PHY_WRITE(sc, YT8511_REG_DATA, data);
+
+       PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
+       data = PHY_READ(sc, YT8511_REG_DATA);
+       data &= ~YT8521_RX_DELAY_SEL_MASK;
+       data |= (((rx_delay + 75) / 150) << YT8521_RX_DELAY_SEL_SHIFT);
+       data &= ~YT8521_TX_DELAY_SEL_MASK;
+       data |= (((tx_delay + 75) / 150) << YT8521_TX_DELAY_SEL_SHIFT);
+       PHY_WRITE(sc, YT8511_REG_DATA, data);
+
+       /* Restore address register. */
+       PHY_WRITE(sc, YT8511_REG_ADDR, addr);
+}
+
+void
+ytphy_yt8521_update(struct mii_softc *sc)
+{
+#ifdef __HAVE_FDT
+       struct mii_data *mii = sc->mii_pdata;
+       int tx_clk_adj_en;
+       int tx_clk_inv = 0;
+       uint16_t addr, data;
+
+       if (sc->mii_media_active == mii->mii_media_active)
+               return;
+
+       tx_clk_adj_en = OF_getpropbool(mii->mii_node,
+           "motorcomm,tx-clk-adj-enabled");
+       if (!tx_clk_adj_en)
+               return;
+
+       switch (IFM_SUBTYPE(mii->mii_media_active)) {
+       case IFM_1000_T:
+               tx_clk_inv = OF_getpropbool(mii->mii_node,
+                   "motorcomm,tx-clk-1000-inverted");
+               break;
+       case IFM_100_TX:
+               tx_clk_inv = OF_getpropbool(mii->mii_node,
+                   "motorcomm,tx-clk-100-inverted");
+               break;
+       case IFM_10_T:
+               tx_clk_inv = OF_getpropbool(mii->mii_node,
+                   "motorcomm,tx-clk-10-inverted");
+               break;
+       }
+
+       /* Save address register. */
+       addr = PHY_READ(sc, YT8511_REG_ADDR);
+
+       PHY_WRITE(sc, YT8511_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
+       data = PHY_READ(sc, YT8511_REG_DATA);
+       if (tx_clk_inv)
+               data |= YT8521_TX_CLK_SEL;
+       else
+               data &= ~YT8521_TX_CLK_SEL;
+       PHY_WRITE(sc, YT8511_REG_DATA, data);
+
+       /* Restore address register. */
+       PHY_WRITE(sc, YT8511_REG_ADDR, addr);
+#endif
+}