From: kettenis Date: Sat, 8 Jul 2023 08:18:30 +0000 (+0000) Subject: Add support for the Motorcomm YT8521/YT8531 PHYs. Since these PHYs may X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=2b94700ca7c110378f0b36a4144e242a9b5025c2;p=openbsd Add support for the Motorcomm YT8521/YT8531 PHYs. Since these PHYs may 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@ --- diff --git a/sys/arch/riscv64/conf/GENERIC b/sys/arch/riscv64/conf/GENERIC index acf00b84a25..15a9abfef67 100644 --- a/sys/arch/riscv64/conf/GENERIC +++ b/sys/arch/riscv64/conf/GENERIC @@ -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 diff --git a/sys/arch/riscv64/conf/RAMDISK b/sys/arch/riscv64/conf/RAMDISK index 45bc8983aa0..955be7f7d7b 100644 --- a/sys/arch/riscv64/conf/RAMDISK +++ b/sys/arch/riscv64/conf/RAMDISK @@ -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 diff --git a/sys/dev/fdt/if_dwqe_fdt.c b/sys/dev/fdt/if_dwqe_fdt.c index 1e98c2e9d85..af0f4e47011 100644 --- a/sys/dev/fdt/if_dwqe_fdt.c +++ b/sys/dev/fdt/if_dwqe_fdt.c @@ -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 * Copyright (c) 2017, 2022 Patrick Wildt @@ -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"); diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs index ceed41f5b20..d68fae9765d 100644 --- a/sys/dev/mii/miidevs +++ b/sys/dev/mii/miidevs @@ -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 diff --git a/sys/dev/mii/miivar.h b/sys/dev/mii/miivar.h index e3f50619451..2349072bef2 100644 --- a/sys/dev/mii/miivar.h +++ b/sys/dev/mii/miivar.h @@ -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 diff --git a/sys/dev/mii/ytphy.c b/sys/dev/mii/ytphy.c index 6e3b253f9ac..00aa82e2c9f 100644 --- a/sys/dev/mii/ytphy.c +++ b/sys/dev/mii/ytphy.c @@ -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 @@ -28,6 +28,15 @@ #include #include +#include + +#ifdef __HAVE_FDT +#include +#include +#endif + +#define MII_MODEL_MOTORCOMM_YT8511 0x10 +#define MII_MODEL_MOTORCOMM_YT8521 0x11 #define YT8511_REG_ADDR 0x1e #define YT8511_REG_DATA 0x1f @@ -46,6 +55,15 @@ #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 +}