Home | History | Annotate | Line # | Download | only in mii
      1  1.3     skrll /* $NetBSD: mcommphy.c,v 1.3 2024/10/23 05:55:45 skrll Exp $ */
      2  1.1  jmcneill 
      3  1.1  jmcneill /*
      4  1.1  jmcneill  * Copyright (c) 2022 Jared McNeill <jmcneill (at) invisible.ca>
      5  1.1  jmcneill  * All rights reserved.
      6  1.1  jmcneill  *
      7  1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      8  1.1  jmcneill  * modification, are permitted provided that the following conditions
      9  1.1  jmcneill  * are met:
     10  1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     11  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     12  1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     15  1.1  jmcneill  *
     16  1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  1.1  jmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  1.1  jmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  1.1  jmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  1.1  jmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  1.1  jmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  1.1  jmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  1.1  jmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  1.1  jmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  1.1  jmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  1.1  jmcneill  * POSSIBILITY OF SUCH DAMAGE.
     27  1.1  jmcneill  */
     28  1.1  jmcneill 
     29  1.1  jmcneill /*
     30  1.1  jmcneill  * Motorcomm YT8511C / YT8511H Integrated 10/100/1000 Gigabit Ethernet
     31  1.1  jmcneill  * Transceiver.
     32  1.1  jmcneill  */
     33  1.1  jmcneill 
     34  1.1  jmcneill #include <sys/cdefs.h>
     35  1.3     skrll __KERNEL_RCSID(0, "$NetBSD: mcommphy.c,v 1.3 2024/10/23 05:55:45 skrll Exp $");
     36  1.1  jmcneill 
     37  1.1  jmcneill #include <sys/param.h>
     38  1.1  jmcneill #include <sys/systm.h>
     39  1.1  jmcneill #include <sys/kernel.h>
     40  1.1  jmcneill #include <sys/device.h>
     41  1.1  jmcneill #include <sys/socket.h>
     42  1.1  jmcneill #include <sys/errno.h>
     43  1.1  jmcneill 
     44  1.1  jmcneill #include <net/if.h>
     45  1.1  jmcneill #include <net/if_media.h>
     46  1.1  jmcneill 
     47  1.1  jmcneill #include <dev/mii/mii.h>
     48  1.1  jmcneill #include <dev/mii/miivar.h>
     49  1.1  jmcneill #include <dev/mii/miidevs.h>
     50  1.1  jmcneill 
     51  1.2     skrll #define	YT85X1_MCOMMPHY_OUI		0x000000
     52  1.2     skrll #define	YT8511_MCOMMPHY_MODEL		0x10
     53  1.3     skrll #define	YT8521_MCOMMPHY_MODEL		0x11
     54  1.2     skrll #define	YT85X1_MCOMMPHY_REV		0x0a
     55  1.1  jmcneill 
     56  1.2     skrll #define	YTPHY_EXT_REG_ADDR		0x1e
     57  1.2     skrll #define	YTPHY_EXT_REG_DATA		0x1f
     58  1.1  jmcneill 
     59  1.1  jmcneill /* Extended registers */
     60  1.2     skrll #define	YT8511_CLOCK_GATING_REG		0x0c
     61  1.2     skrll #define	 YT8511_TX_CLK_DELAY_SEL	__BITS(7,4)
     62  1.2     skrll #define	 YT8511_CLK_25M_SEL		__BITS(2,1)
     63  1.2     skrll #define	 YT8511_CLK_25M_SEL_125M	3
     64  1.2     skrll #define	 YT8511_RX_CLK_DELAY_EN		__BIT(0)
     65  1.2     skrll 
     66  1.3     skrll #define	YT8511_DELAY_DRIVE_REG		0x0d
     67  1.3     skrll #define	 YT8511_FE_TX_CLK_DELAY_SEL	__BITS(15,12)
     68  1.3     skrll 
     69  1.3     skrll #define	YT8521_CLOCK_GATING_REG		0x0c
     70  1.3     skrll #define	 YT8521_RX_CLK_EN		__BIT(12)
     71  1.3     skrll 
     72  1.2     skrll #define	YT8511_SLEEP_CONTROL1_REG	0x27
     73  1.2     skrll #define	 YT8511_PLLON_IN_SLP		__BIT(14)
     74  1.1  jmcneill 
     75  1.3     skrll #define	YT8521_SLEEP_CONTROL1_REG	0x27
     76  1.3     skrll #define	 YT8521_PLLON_IN_SLP		__BIT(14)
     77  1.3     skrll 
     78  1.3     skrll #define YT8521_EXT_CHIP_CONFIG		0xa001
     79  1.3     skrll #define  YT8521_RXC_DLY_EN		__BIT(8)
     80  1.3     skrll #define  YT8521_CFG_LDO_MASK		__BITS(5, 4)
     81  1.3     skrll #define   YT8521_CFG_LDO_3V3		0
     82  1.3     skrll #define   YT8521_CFG_LDO_2V5		1
     83  1.3     skrll #define   YT8521_CFG_LDO_1V8		2	/* or 3 */
     84  1.3     skrll 
     85  1.3     skrll #define YT8521_EXT_SDS_CONFIG		0xa002
     86  1.3     skrll 
     87  1.3     skrll #define YT8521_EXT_RGMII_CONFIG1	0xa003
     88  1.3     skrll #define  YT8521_TX_CLK_SEL_INV		__BIT(14)
     89  1.3     skrll #define  YT8521_RX_DELAY_SEL_MASK	__BITS(13, 10)
     90  1.3     skrll #define  YT8521_FE_TX_DELAY_SEL_MASK	__BITS(7, 4)
     91  1.3     skrll #define  YT8521_GE_TX_DELAY_SEL_MASK	__BITS(3, 0)
     92  1.3     skrll #define  YT8521_DELAY_PS(ps)		((ps) / 150)
     93  1.3     skrll #define YT8521_DELAY_DEFAULT		1950
     94  1.3     skrll 
     95  1.3     skrll #define YT8521_EXT_RGMII_CONFIG2	0xa004
     96  1.3     skrll 
     97  1.3     skrll #define YT8521_EXT_PAD_DRIVE_STRENGTH	0xa010
     98  1.3     skrll #define  YT8531_RGMII_RXC_DS_MASK	__BITS(15, 13)
     99  1.3     skrll #define  YT8531_RGMII_RXD_DS_HIMASK	__BIT(12)
    100  1.3     skrll #define  YT8531_RGMII_RXD_DS_LOMASK	__BITS(5, 4)
    101  1.3     skrll #define YT8531_RGMII_RXD_DS_MASK \
    102  1.3     skrll     (YT8531_RGMII_RXD_DS_HIMASK | YT8531_RGMII_RXD_DS_LOMASK)
    103  1.3     skrll 
    104  1.3     skrll #define YT8531_RGMII_RXD_DS_HIBITS	__BIT(2)
    105  1.3     skrll #define YT8531_RGMII_RXD_DS_LOBITS	__BITS(1, 0)
    106  1.3     skrll 
    107  1.3     skrll CTASSERT(__SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_HIMASK) ==
    108  1.3     skrll 	 __SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_HIBITS));
    109  1.3     skrll CTASSERT(__SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_LOMASK) ==
    110  1.3     skrll 	 __SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_LOBITS));
    111  1.3     skrll 
    112  1.3     skrll #define YT8531_DEFAULT_DS		3
    113  1.3     skrll 
    114  1.3     skrll #define YT8521_EXT_SYNCE_CFG		0xa012
    115  1.3     skrll #define  YT8531_EN_SYNC_E		__BIT(6)
    116  1.3     skrll #define  YT8531_CLK_FRE_SEL_125M	__BIT(4)
    117  1.3     skrll #define  YT8531_CLK_SRC_SEL_MASK	__BITS(3, 1)
    118  1.3     skrll #define   YT8531_CLK_SRC_SEL_PLL_125M	0
    119  1.3     skrll #define   YT8531_CLK_SRC_SEL_REF_25M	4
    120  1.3     skrll 
    121  1.3     skrll 
    122  1.3     skrll typedef enum mcommtype {
    123  1.3     skrll     YTUNK,
    124  1.3     skrll     YT8511,
    125  1.3     skrll     YT8521,
    126  1.3     skrll     YT8531,
    127  1.3     skrll } mcommtype_t;
    128  1.3     skrll 
    129  1.3     skrll struct mcomm_softc {
    130  1.3     skrll 	struct mii_softc	sc_miisc;
    131  1.3     skrll 
    132  1.3     skrll 	mcommtype_t		sc_type;
    133  1.3     skrll 
    134  1.3     skrll 	bool			sc_tx_clk_adj_enabled;
    135  1.3     skrll 	bool			sc_tx_clk_10_inverted;
    136  1.3     skrll 	bool			sc_tx_clk_100_inverted;
    137  1.3     skrll 	bool			sc_tx_clk_1000_inverted;
    138  1.3     skrll 	u_int			sc_clk_out_frequency_hz;
    139  1.3     skrll 	u_int			sc_rx_clk_drv_microamp;
    140  1.3     skrll 	u_int			sc_rx_data_drv_microamp;
    141  1.3     skrll 	u_int			sc_rx_internal_delay_ps;
    142  1.3     skrll 	u_int			sc_tx_internal_delay_ps;
    143  1.3     skrll };
    144  1.3     skrll 
    145  1.1  jmcneill static int	mcommphymatch(device_t, cfdata_t, void *);
    146  1.1  jmcneill static void	mcommphyattach(device_t, device_t, void *);
    147  1.1  jmcneill 
    148  1.3     skrll CFATTACH_DECL_NEW(mcommphy, sizeof(struct mcomm_softc),
    149  1.1  jmcneill     mcommphymatch, mcommphyattach, mii_phy_detach, mii_phy_activate);
    150  1.1  jmcneill 
    151  1.1  jmcneill static int	mcommphy_service(struct mii_softc *, struct mii_data *, int);
    152  1.3     skrll static void	mcommphy_reset(struct mii_softc *);
    153  1.1  jmcneill 
    154  1.1  jmcneill static const struct mii_phy_funcs mcommphy_funcs = {
    155  1.3     skrll 	.pf_service = mcommphy_service,
    156  1.3     skrll 	.pf_status = ukphy_status,
    157  1.3     skrll 	.pf_reset = mcommphy_reset,
    158  1.3     skrll };
    159  1.3     skrll 
    160  1.3     skrll static const struct mii_phydesc mcommphys[] = {
    161  1.3     skrll 	MII_PHY_DESC(MOTORCOMM, YT8531),
    162  1.3     skrll 	MII_PHY_END,
    163  1.1  jmcneill };
    164  1.1  jmcneill 
    165  1.3     skrll static void
    166  1.3     skrll mcomm_yt8531properties(struct mcomm_softc *msc, prop_dictionary_t dict)
    167  1.3     skrll {
    168  1.3     skrll 	struct mii_softc * const sc = &msc->sc_miisc;
    169  1.3     skrll 
    170  1.3     skrll 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-adj-enabled",
    171  1.3     skrll 	    &msc->sc_tx_clk_adj_enabled)) {
    172  1.3     skrll 		msc->sc_tx_clk_adj_enabled = false;
    173  1.3     skrll 	} else {
    174  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    175  1.3     skrll 		    "motorcomm,tx-clk-adj-enabled is %s\n",
    176  1.3     skrll 		    msc->sc_tx_clk_adj_enabled ? "true" : "false");
    177  1.3     skrll 	}
    178  1.3     skrll 
    179  1.3     skrll 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-10-inverted",
    180  1.3     skrll 	    &msc->sc_tx_clk_10_inverted)) {
    181  1.3     skrll 		msc->sc_tx_clk_10_inverted = false;
    182  1.3     skrll 	} else {
    183  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    184  1.3     skrll 		    "motorcomm,tx_clk_10_inverted is %s\n",
    185  1.3     skrll 		    msc->sc_tx_clk_10_inverted ? "true" : "false");
    186  1.3     skrll 	}
    187  1.3     skrll 
    188  1.3     skrll 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-100-inverted",
    189  1.3     skrll 	    &msc->sc_tx_clk_100_inverted)) {
    190  1.3     skrll 		msc->sc_tx_clk_100_inverted = false;
    191  1.3     skrll 	} else {
    192  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    193  1.3     skrll 		    "motorcomm,tx-clk-100-inverted is %s\n",
    194  1.3     skrll 		    msc->sc_tx_clk_100_inverted ? "true" : "false");
    195  1.3     skrll 	}
    196  1.3     skrll 
    197  1.3     skrll 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-1000-inverted",
    198  1.3     skrll 	    &msc->sc_tx_clk_1000_inverted)) {
    199  1.3     skrll 		msc->sc_tx_clk_1000_inverted = false;
    200  1.3     skrll 	} else {
    201  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    202  1.3     skrll 		    "motorcomm,tx-clk-1000-inverted is %s\n",
    203  1.3     skrll 		    msc->sc_tx_clk_1000_inverted ? "true" : "false");
    204  1.3     skrll 	}
    205  1.3     skrll 
    206  1.3     skrll 	if (!prop_dictionary_get_uint32(dict, "motorcomm,clk-out-frequency-hz",
    207  1.3     skrll 	    &msc->sc_clk_out_frequency_hz)) {
    208  1.3     skrll 		msc->sc_clk_out_frequency_hz = 0;
    209  1.3     skrll 	} else {
    210  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    211  1.3     skrll 		    "motorcomm,clk-out-frequency-hz is %u\n",
    212  1.3     skrll 		    msc->sc_clk_out_frequency_hz);
    213  1.3     skrll 	}
    214  1.3     skrll 
    215  1.3     skrll 	if (!prop_dictionary_get_uint32(dict, "motorcomm,rx-clk-drv-microamp",
    216  1.3     skrll 	    &msc->sc_rx_clk_drv_microamp)) {
    217  1.3     skrll 		aprint_debug_dev(sc->mii_dev,
    218  1.3     skrll 		    "motorcomm,rx-clk-drv-microamp not found\n");
    219  1.3     skrll 	} else {
    220  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    221  1.3     skrll 		    "rx-clk-drv-microamp is %u\n",
    222  1.3     skrll 		    msc->sc_rx_clk_drv_microamp);
    223  1.3     skrll 	}
    224  1.3     skrll 
    225  1.3     skrll 	if (!prop_dictionary_get_uint32(dict, "motorcomm,rx-data-drv-microamp",
    226  1.3     skrll 	    &msc->sc_rx_data_drv_microamp)) {
    227  1.3     skrll 		aprint_debug_dev(sc->mii_dev,
    228  1.3     skrll 		    "motorcomm,rx-data-drv-microamp not found\n");
    229  1.3     skrll 	} else {
    230  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    231  1.3     skrll 		    "motorcomm,rx-data-drv-microamp is %u\n",
    232  1.3     skrll 		    msc->sc_rx_data_drv_microamp);
    233  1.3     skrll 	}
    234  1.3     skrll 
    235  1.3     skrll 	if (!prop_dictionary_get_uint32(dict, "rx-internal-delay-ps",
    236  1.3     skrll 	    &msc->sc_rx_internal_delay_ps)) {
    237  1.3     skrll 		aprint_debug_dev(sc->mii_dev,
    238  1.3     skrll 		    "rx-internal-delay-ps not found\n");
    239  1.3     skrll 	} else {
    240  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    241  1.3     skrll 		    "rx-internal-delay-ps is %u\n",
    242  1.3     skrll 		    msc->sc_rx_internal_delay_ps);
    243  1.3     skrll 	}
    244  1.3     skrll 
    245  1.3     skrll 	if (!prop_dictionary_get_uint32(dict, "tx-internal-delay-ps",
    246  1.3     skrll 	    &msc->sc_tx_internal_delay_ps)) {
    247  1.3     skrll 		aprint_debug_dev(sc->mii_dev,
    248  1.3     skrll 		    "tx-internal-delay-ps not found\n");
    249  1.3     skrll 	} else {
    250  1.3     skrll 		aprint_verbose_dev(sc->mii_dev,
    251  1.3     skrll 		    "tx-internal-delay-ps is %u\n",
    252  1.3     skrll 		    msc->sc_tx_internal_delay_ps);
    253  1.3     skrll 	}
    254  1.3     skrll }
    255  1.3     skrll 
    256  1.3     skrll static bool
    257  1.3     skrll mcommphy_isyt8511(struct mii_attach_args *ma)
    258  1.1  jmcneill {
    259  1.1  jmcneill 
    260  1.1  jmcneill 	/*
    261  1.1  jmcneill 	 * The YT8511C reports an OUI of 0. Best we can do here is to match
    262  1.1  jmcneill 	 * exactly the contents of the PHY identification registers.
    263  1.1  jmcneill 	 */
    264  1.2     skrll 	if (MII_OUI(ma->mii_id1, ma->mii_id2) == YT85X1_MCOMMPHY_OUI &&
    265  1.2     skrll 	    MII_MODEL(ma->mii_id2) == YT8511_MCOMMPHY_MODEL &&
    266  1.2     skrll 	    MII_REV(ma->mii_id2) == YT85X1_MCOMMPHY_REV) {
    267  1.3     skrll 		return true;
    268  1.1  jmcneill 	}
    269  1.3     skrll 	return false;
    270  1.3     skrll }
    271  1.1  jmcneill 
    272  1.1  jmcneill 
    273  1.3     skrll static int
    274  1.3     skrll mcommphymatch(device_t parent, cfdata_t match, void *aux)
    275  1.1  jmcneill {
    276  1.1  jmcneill 	struct mii_attach_args *ma = aux;
    277  1.1  jmcneill 
    278  1.3     skrll 	if (mii_phy_match(ma, mcommphys) != NULL)
    279  1.3     skrll 		return 10;
    280  1.1  jmcneill 
    281  1.3     skrll 	if (mcommphy_isyt8511(ma))
    282  1.3     skrll 		return 10;
    283  1.1  jmcneill 
    284  1.3     skrll 	return 0;
    285  1.3     skrll }
    286  1.1  jmcneill 
    287  1.3     skrll static void
    288  1.3     skrll mcomm_yt8511_init(struct mcomm_softc *msc)
    289  1.3     skrll {
    290  1.3     skrll 	struct mii_softc *sc = &msc->sc_miisc;
    291  1.3     skrll 	uint16_t oldaddr, data;
    292  1.1  jmcneill 
    293  1.2     skrll 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    294  1.1  jmcneill 
    295  1.2     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8511_CLOCK_GATING_REG);
    296  1.3     skrll 
    297  1.2     skrll 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    298  1.3     skrll 
    299  1.2     skrll 	data &= ~YT8511_CLK_25M_SEL;
    300  1.2     skrll 	data |= __SHIFTIN(YT8511_CLK_25M_SEL_125M, YT8511_CLK_25M_SEL);
    301  1.1  jmcneill 	if (ISSET(sc->mii_flags, MIIF_RXID)) {
    302  1.2     skrll 		data |= YT8511_RX_CLK_DELAY_EN;
    303  1.1  jmcneill 	} else {
    304  1.2     skrll 		data &= ~YT8511_RX_CLK_DELAY_EN;
    305  1.1  jmcneill 	}
    306  1.2     skrll 	data &= ~YT8511_TX_CLK_DELAY_SEL;
    307  1.1  jmcneill 	if (ISSET(sc->mii_flags, MIIF_TXID)) {
    308  1.2     skrll 		data |= __SHIFTIN(0xf, YT8511_TX_CLK_DELAY_SEL);
    309  1.1  jmcneill 	} else {
    310  1.2     skrll 		data |= __SHIFTIN(0x2, YT8511_TX_CLK_DELAY_SEL);
    311  1.1  jmcneill 	}
    312  1.2     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    313  1.1  jmcneill 
    314  1.2     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8511_SLEEP_CONTROL1_REG);
    315  1.2     skrll 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    316  1.3     skrll 
    317  1.2     skrll 	data |= YT8511_PLLON_IN_SLP;
    318  1.3     skrll 
    319  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    320  1.3     skrll 
    321  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    322  1.3     skrll }
    323  1.3     skrll 
    324  1.3     skrll 
    325  1.3     skrll 
    326  1.3     skrll static void
    327  1.3     skrll mcomm_yt8521_init(struct mcomm_softc *msc)
    328  1.3     skrll {
    329  1.3     skrll 	struct mii_softc *sc = &msc->sc_miisc;
    330  1.3     skrll 	bool rx_delay_en = false;
    331  1.3     skrll 	u_int rx_delay_val;
    332  1.3     skrll 	u_int tx_delay_val;
    333  1.3     skrll 	uint16_t oldaddr, data;
    334  1.3     skrll 
    335  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    336  1.3     skrll 
    337  1.3     skrll 	u_int rx_delay = msc->sc_rx_internal_delay_ps;
    338  1.3     skrll 	if (rx_delay <= 15 * 150 && rx_delay % 150 == 0) {
    339  1.3     skrll 		rx_delay_val = YT8521_DELAY_PS(rx_delay);
    340  1.3     skrll 	} else {
    341  1.3     skrll 		/* It's OK if this underflows */
    342  1.3     skrll 		rx_delay -= 1900;
    343  1.3     skrll 		if (rx_delay <= 15 * 150 && rx_delay % 150 == 0) {
    344  1.3     skrll 			rx_delay_en = true;
    345  1.3     skrll 			rx_delay_val = YT8521_DELAY_PS(rx_delay);
    346  1.3     skrll 		} else {
    347  1.3     skrll 			rx_delay_val = YT8521_DELAY_PS(YT8521_DELAY_DEFAULT);
    348  1.3     skrll 		}
    349  1.3     skrll 	}
    350  1.3     skrll 
    351  1.3     skrll 	u_int tx_delay = msc->sc_tx_internal_delay_ps;
    352  1.3     skrll 	if (tx_delay <= 15 * 150 && tx_delay % 150 == 0) {
    353  1.3     skrll 		tx_delay_val = YT8521_DELAY_PS(tx_delay);
    354  1.3     skrll 	} else {
    355  1.3     skrll 		tx_delay_val = YT8521_DELAY_PS(YT8521_DELAY_DEFAULT);
    356  1.3     skrll 	}
    357  1.3     skrll 
    358  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_CHIP_CONFIG);
    359  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    360  1.3     skrll 
    361  1.3     skrll 	if (rx_delay_en)
    362  1.3     skrll 		data |= YT8521_RXC_DLY_EN;
    363  1.3     skrll 	else
    364  1.3     skrll 		data &= ~YT8521_RXC_DLY_EN;
    365  1.3     skrll 
    366  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    367  1.3     skrll 
    368  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
    369  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    370  1.3     skrll 
    371  1.3     skrll 	data &= ~(YT8521_RX_DELAY_SEL_MASK | YT8521_GE_TX_DELAY_SEL_MASK);
    372  1.3     skrll 	// XXX FE?
    373  1.3     skrll 	data |=
    374  1.3     skrll 	    __SHIFTIN(rx_delay_val, YT8521_RX_DELAY_SEL_MASK) |
    375  1.3     skrll 	    __SHIFTIN(tx_delay_val, YT8521_GE_TX_DELAY_SEL_MASK);
    376  1.3     skrll 
    377  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    378  1.3     skrll 
    379  1.3     skrll 	/* Restore address register. */
    380  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    381  1.3     skrll }
    382  1.3     skrll 
    383  1.3     skrll struct mcomm_ytphy_ds_map {
    384  1.3     skrll 	u_int microamps;
    385  1.3     skrll 	u_int ds;
    386  1.3     skrll };
    387  1.3     skrll 
    388  1.3     skrll struct mcomm_ytphy_ds_map mcomm_1d8v_ds_map[] = {
    389  1.3     skrll 	{ .microamps = 1200, .ds = 0 },
    390  1.3     skrll 	{ .microamps = 2100, .ds = 1 },
    391  1.3     skrll 	{ .microamps = 2700, .ds = 2 },
    392  1.3     skrll 	{ .microamps = 2910, .ds = 3 },
    393  1.3     skrll 	{ .microamps = 3110, .ds = 4 },
    394  1.3     skrll 	{ .microamps = 3600, .ds = 5 },
    395  1.3     skrll 	{ .microamps = 3970, .ds = 6 },
    396  1.3     skrll 	{ .microamps = 4350, .ds = 7 },
    397  1.3     skrll };
    398  1.3     skrll struct mcomm_ytphy_ds_map mcomm_3d3v_ds_map[] = {
    399  1.3     skrll 	{ .microamps = 3070, .ds = 0 },
    400  1.3     skrll 	{ .microamps = 4080, .ds = 1 },
    401  1.3     skrll 	{ .microamps = 4370, .ds = 2 },
    402  1.3     skrll 	{ .microamps = 4680, .ds = 3 },
    403  1.3     skrll 	{ .microamps = 5020, .ds = 4 },
    404  1.3     skrll 	{ .microamps = 5450, .ds = 5 },
    405  1.3     skrll 	{ .microamps = 5740, .ds = 6 },
    406  1.3     skrll 	{ .microamps = 6140, .ds = 7 },
    407  1.3     skrll };
    408  1.3     skrll 
    409  1.3     skrll static u_int
    410  1.3     skrll mcomm_yt8531_ds(struct mcomm_softc *msc,
    411  1.3     skrll     struct mcomm_ytphy_ds_map *ds_map, size_t n,
    412  1.3     skrll     u_int microamps, u_int millivolts)
    413  1.3     skrll {
    414  1.3     skrll 	for (size_t i = 0; i < n; i++) {
    415  1.3     skrll 		if (ds_map[i].microamps == microamps)
    416  1.3     skrll 			return ds_map[i].ds;
    417  1.3     skrll 	}
    418  1.3     skrll 	if (microamps) {
    419  1.3     skrll 		struct mii_softc *sc = &msc->sc_miisc;
    420  1.3     skrll 
    421  1.3     skrll 		aprint_error_dev(sc->mii_dev, "unknown drive strength "
    422  1.3     skrll 		    "(%u uA at %u mV)", microamps, millivolts);
    423  1.3     skrll 	}
    424  1.3     skrll 	return YT8531_DEFAULT_DS;
    425  1.3     skrll }
    426  1.3     skrll 
    427  1.3     skrll static void
    428  1.3     skrll mcomm_yt8531_init(struct mcomm_softc *msc)
    429  1.3     skrll {
    430  1.3     skrll 	struct mii_softc *sc = &msc->sc_miisc;
    431  1.3     skrll 	uint16_t oldaddr, data;
    432  1.3     skrll 
    433  1.3     skrll 	mcomm_yt8521_init(msc);
    434  1.3     skrll 
    435  1.3     skrll 	/* Save address register. */
    436  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    437  1.3     skrll 
    438  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_CHIP_CONFIG);
    439  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    440  1.3     skrll 
    441  1.3     skrll 	struct mcomm_ytphy_ds_map *ds_map = NULL;
    442  1.3     skrll 	size_t ds_mapsize;
    443  1.3     skrll 	u_int millivolts = 1800;
    444  1.3     skrll 	switch (__SHIFTOUT(data, YT8521_CFG_LDO_MASK)) {
    445  1.3     skrll 	case YT8521_CFG_LDO_3V3:
    446  1.3     skrll 		ds_map = mcomm_3d3v_ds_map;
    447  1.3     skrll 		ds_mapsize = __arraycount(mcomm_3d3v_ds_map);
    448  1.3     skrll 		millivolts = 3300;
    449  1.3     skrll 		break;
    450  1.3     skrll 	case YT8521_CFG_LDO_2V5:
    451  1.3     skrll 		millivolts = 2500;
    452  1.3     skrll 		break;
    453  1.3     skrll 	default:
    454  1.3     skrll 		ds_map = mcomm_1d8v_ds_map;
    455  1.3     skrll 		ds_mapsize = __arraycount(mcomm_1d8v_ds_map);
    456  1.3     skrll 		break;
    457  1.3     skrll 	}
    458  1.3     skrll 
    459  1.3     skrll 	if (ds_map) {
    460  1.3     skrll 		u_int rx_clk_ds = mcomm_yt8531_ds(msc, ds_map, ds_mapsize,
    461  1.3     skrll 		    msc->sc_rx_clk_drv_microamp, millivolts);
    462  1.3     skrll 		u_int rx_data_ds = mcomm_yt8531_ds(msc, ds_map, ds_mapsize,
    463  1.3     skrll 		    msc->sc_rx_data_drv_microamp, millivolts);
    464  1.3     skrll 
    465  1.3     skrll 		PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_PAD_DRIVE_STRENGTH);
    466  1.3     skrll 		PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    467  1.3     skrll 
    468  1.3     skrll 		data &= ~(YT8531_RGMII_RXC_DS_MASK | YT8531_RGMII_RXD_DS_MASK);
    469  1.3     skrll 
    470  1.3     skrll 		u_int rx_data_ds_hi =
    471  1.3     skrll 		    __SHIFTOUT(rx_data_ds, YT8531_RGMII_RXD_DS_HIBITS);
    472  1.3     skrll 		u_int rx_data_ds_lo =
    473  1.3     skrll 		    __SHIFTOUT(rx_data_ds, YT8531_RGMII_RXD_DS_LOBITS);
    474  1.3     skrll 		data |=
    475  1.3     skrll 		    __SHIFTIN(rx_clk_ds, YT8531_RGMII_RXC_DS_MASK) |
    476  1.3     skrll 		    __SHIFTIN(rx_data_ds_hi, YT8531_RGMII_RXD_DS_HIMASK) |
    477  1.3     skrll 		    __SHIFTIN(rx_data_ds_lo, YT8531_RGMII_RXD_DS_LOMASK);
    478  1.3     skrll 
    479  1.3     skrll 		PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    480  1.3     skrll 	}
    481  1.3     skrll 
    482  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_SYNCE_CFG);
    483  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    484  1.3     skrll 
    485  1.3     skrll 	data &= ~(YT8531_EN_SYNC_E | YT8531_CLK_SRC_SEL_MASK);
    486  1.3     skrll 
    487  1.3     skrll 	switch (msc->sc_clk_out_frequency_hz) {
    488  1.3     skrll 	case 125000000:
    489  1.3     skrll 		data |= YT8531_EN_SYNC_E;
    490  1.3     skrll 		data |= YT8531_CLK_FRE_SEL_125M;
    491  1.3     skrll 		data |= __SHIFTIN(YT8531_CLK_SRC_SEL_PLL_125M, YT8531_CLK_SRC_SEL_MASK);
    492  1.3     skrll 		break;
    493  1.3     skrll 	case 25000000:
    494  1.3     skrll 		data |= YT8531_EN_SYNC_E;
    495  1.3     skrll 		data |= __SHIFTIN(YT8531_CLK_SRC_SEL_REF_25M, YT8531_CLK_SRC_SEL_MASK);
    496  1.3     skrll 		break;
    497  1.3     skrll 	default:
    498  1.3     skrll 		break;
    499  1.3     skrll 	}
    500  1.3     skrll 
    501  1.2     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    502  1.1  jmcneill 
    503  1.3     skrll 	/* Restore address register. */
    504  1.2     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    505  1.3     skrll }
    506  1.3     skrll 
    507  1.3     skrll 
    508  1.3     skrll static void
    509  1.3     skrll mcommphy_reset(struct mii_softc *sc)
    510  1.3     skrll {
    511  1.3     skrll 	struct mcomm_softc * const msc =
    512  1.3     skrll 	    container_of(sc, struct mcomm_softc, sc_miisc);
    513  1.3     skrll 
    514  1.3     skrll 	KASSERT(mii_locked(sc->mii_pdata));
    515  1.3     skrll 
    516  1.3     skrll 	mii_phy_reset(sc);
    517  1.3     skrll 
    518  1.3     skrll 	switch (msc->sc_type) {
    519  1.3     skrll 	case YT8511:
    520  1.3     skrll 		mcomm_yt8511_init(msc);
    521  1.3     skrll 		break;
    522  1.3     skrll 	case YT8531:
    523  1.3     skrll 		mcomm_yt8531_init(msc);
    524  1.3     skrll 		break;
    525  1.3     skrll 	default:
    526  1.3     skrll 		return;
    527  1.3     skrll 	}
    528  1.3     skrll }
    529  1.3     skrll 
    530  1.3     skrll 
    531  1.3     skrll static void
    532  1.3     skrll mcommphyattach(device_t parent, device_t self, void *aux)
    533  1.3     skrll {
    534  1.3     skrll 	struct mcomm_softc *msc = device_private(self);
    535  1.3     skrll 	struct mii_softc *sc = &msc->sc_miisc;
    536  1.3     skrll 	struct mii_attach_args *ma = aux;
    537  1.3     skrll 	struct mii_data *mii = ma->mii_data;
    538  1.3     skrll 
    539  1.3     skrll 	msc->sc_type = YTUNK;
    540  1.3     skrll 	if (mcommphy_isyt8511(ma)) {
    541  1.3     skrll 		msc->sc_type = YT8511;
    542  1.3     skrll 		aprint_normal(": Motorcomm YT8511 GbE PHY\n");
    543  1.3     skrll 	} else {
    544  1.3     skrll 		KASSERT(mii_phy_match(ma, mcommphys) != NULL);
    545  1.3     skrll 		msc->sc_type = YT8531;
    546  1.3     skrll 		aprint_normal(": Motorcomm YT8531 GbE PHY\n");
    547  1.3     skrll 	}
    548  1.3     skrll 	aprint_naive(": Media interface\n");
    549  1.3     skrll 
    550  1.3     skrll 	sc->mii_dev = self;
    551  1.3     skrll 	sc->mii_inst = mii->mii_instance;
    552  1.3     skrll 	sc->mii_phy = ma->mii_phyno;
    553  1.3     skrll 	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
    554  1.3     skrll 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
    555  1.3     skrll 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
    556  1.3     skrll 	sc->mii_funcs = &mcommphy_funcs;
    557  1.3     skrll 	sc->mii_pdata = mii;
    558  1.3     skrll 	sc->mii_flags = ma->mii_flags;
    559  1.3     skrll 
    560  1.3     skrll 	prop_dictionary_t dict = device_properties(parent);
    561  1.3     skrll 	switch (msc->sc_type) {
    562  1.3     skrll 	case YT8521:
    563  1.3     skrll 	case YT8531:
    564  1.3     skrll 		/* Default values */
    565  1.3     skrll 		msc->sc_rx_internal_delay_ps = YT8521_DELAY_DEFAULT;
    566  1.3     skrll 		msc->sc_tx_internal_delay_ps = YT8521_DELAY_DEFAULT;
    567  1.3     skrll 
    568  1.3     skrll 		mcomm_yt8531properties(msc, dict);
    569  1.3     skrll 		break;
    570  1.3     skrll 	default:
    571  1.3     skrll 		break;
    572  1.3     skrll 	}
    573  1.3     skrll 
    574  1.3     skrll 	mii_lock(mii);
    575  1.3     skrll 
    576  1.3     skrll 	PHY_RESET(sc);
    577  1.1  jmcneill 
    578  1.1  jmcneill 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
    579  1.1  jmcneill 	sc->mii_capabilities &= ma->mii_capmask;
    580  1.1  jmcneill 	if (sc->mii_capabilities & BMSR_EXTSTAT)
    581  1.1  jmcneill 		PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
    582  1.1  jmcneill 
    583  1.1  jmcneill 	mii_unlock(mii);
    584  1.1  jmcneill 
    585  1.1  jmcneill 	mii_phy_add_media(sc);
    586  1.1  jmcneill }
    587  1.1  jmcneill 
    588  1.3     skrll static void
    589  1.3     skrll ytphy_yt8521_update(struct mcomm_softc *msc)
    590  1.3     skrll {
    591  1.3     skrll 	struct mii_softc *sc = &msc->sc_miisc;
    592  1.3     skrll 	struct mii_data *mii = sc->mii_pdata;
    593  1.3     skrll 	bool tx_clk_inv = false;
    594  1.3     skrll 	uint16_t oldaddr, data;
    595  1.3     skrll 
    596  1.3     skrll 	if (sc->mii_media_active == mii->mii_media_active)
    597  1.3     skrll 		return;
    598  1.3     skrll 
    599  1.3     skrll 	if (!msc->sc_tx_clk_adj_enabled)
    600  1.3     skrll 		return;
    601  1.3     skrll 
    602  1.3     skrll 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
    603  1.3     skrll 	case IFM_1000_T:
    604  1.3     skrll 		tx_clk_inv = msc->sc_tx_clk_1000_inverted;
    605  1.3     skrll 		break;
    606  1.3     skrll 	case IFM_100_TX:
    607  1.3     skrll 		tx_clk_inv = msc->sc_tx_clk_100_inverted;
    608  1.3     skrll 		break;
    609  1.3     skrll 	case IFM_10_T:
    610  1.3     skrll 		tx_clk_inv = msc->sc_tx_clk_10_inverted;
    611  1.3     skrll 		break;
    612  1.3     skrll 	}
    613  1.3     skrll 
    614  1.3     skrll 	/* Save address register. */
    615  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    616  1.3     skrll 
    617  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
    618  1.3     skrll 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    619  1.3     skrll 
    620  1.3     skrll 	if (tx_clk_inv)
    621  1.3     skrll 		data |= YT8521_TX_CLK_SEL_INV;
    622  1.3     skrll 	else
    623  1.3     skrll 		data &= ~YT8521_TX_CLK_SEL_INV;
    624  1.3     skrll 
    625  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    626  1.3     skrll 
    627  1.3     skrll 	/* Restore address register. */
    628  1.3     skrll 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    629  1.3     skrll }
    630  1.3     skrll 
    631  1.1  jmcneill static int
    632  1.1  jmcneill mcommphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
    633  1.1  jmcneill {
    634  1.1  jmcneill 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    635  1.3     skrll 	struct mcomm_softc * const msc =
    636  1.3     skrll 	    container_of(sc, struct mcomm_softc, sc_miisc);
    637  1.1  jmcneill 
    638  1.1  jmcneill 	KASSERT(mii_locked(mii));
    639  1.1  jmcneill 
    640  1.1  jmcneill 	switch (cmd) {
    641  1.1  jmcneill 	case MII_POLLSTAT:
    642  1.1  jmcneill 		/* If we're not polling our PHY instance, just return. */
    643  1.1  jmcneill 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    644  1.1  jmcneill 			return 0;
    645  1.1  jmcneill 		break;
    646  1.1  jmcneill 
    647  1.1  jmcneill 	case MII_MEDIACHG:
    648  1.1  jmcneill 		/* If the interface is not up, don't do anything. */
    649  1.1  jmcneill 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
    650  1.1  jmcneill 			break;
    651  1.1  jmcneill 
    652  1.1  jmcneill 		mii_phy_setmedia(sc);
    653  1.1  jmcneill 		break;
    654  1.1  jmcneill 
    655  1.1  jmcneill 	case MII_TICK:
    656  1.1  jmcneill 		/* If we're not currently selected, just return. */
    657  1.1  jmcneill 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    658  1.1  jmcneill 			return 0;
    659  1.1  jmcneill 
    660  1.1  jmcneill 		if (mii_phy_tick(sc) == EJUSTRETURN)
    661  1.1  jmcneill 			return 0;
    662  1.1  jmcneill 		break;
    663  1.1  jmcneill 
    664  1.1  jmcneill 	case MII_DOWN:
    665  1.1  jmcneill 		mii_phy_down(sc);
    666  1.1  jmcneill 		return 0;
    667  1.1  jmcneill 	}
    668  1.1  jmcneill 
    669  1.1  jmcneill 	/* Update the media status. */
    670  1.1  jmcneill 	mii_phy_status(sc);
    671  1.1  jmcneill 
    672  1.1  jmcneill 	/* Callback if something changed. */
    673  1.3     skrll 	if (msc->sc_type != YT8511)
    674  1.3     skrll 		ytphy_yt8521_update(msc);
    675  1.3     skrll 
    676  1.1  jmcneill 	mii_phy_update(sc, cmd);
    677  1.1  jmcneill 	return 0;
    678  1.1  jmcneill }
    679