Home | History | Annotate | Line # | Download | only in mii
mcommphy.c revision 1.1.10.1
      1  1.1.10.1  perseant /* $NetBSD: mcommphy.c,v 1.1.10.1 2025/08/02 05:56:43 perseant 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.1.10.1  perseant __KERNEL_RCSID(0, "$NetBSD: mcommphy.c,v 1.1.10.1 2025/08/02 05:56:43 perseant 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.1.10.1  perseant #define	YT85X1_MCOMMPHY_OUI		0x000000
     52  1.1.10.1  perseant #define	YT8511_MCOMMPHY_MODEL		0x10
     53  1.1.10.1  perseant #define	YT8521_MCOMMPHY_MODEL		0x11
     54  1.1.10.1  perseant #define	YT85X1_MCOMMPHY_REV		0x0a
     55       1.1  jmcneill 
     56  1.1.10.1  perseant #define	YTPHY_EXT_REG_ADDR		0x1e
     57  1.1.10.1  perseant #define	YTPHY_EXT_REG_DATA		0x1f
     58       1.1  jmcneill 
     59       1.1  jmcneill /* Extended registers */
     60  1.1.10.1  perseant #define	YT8511_CLOCK_GATING_REG		0x0c
     61  1.1.10.1  perseant #define	 YT8511_TX_CLK_DELAY_SEL	__BITS(7,4)
     62  1.1.10.1  perseant #define	 YT8511_CLK_25M_SEL		__BITS(2,1)
     63  1.1.10.1  perseant #define	 YT8511_CLK_25M_SEL_125M	3
     64  1.1.10.1  perseant #define	 YT8511_RX_CLK_DELAY_EN		__BIT(0)
     65  1.1.10.1  perseant 
     66  1.1.10.1  perseant #define	YT8511_DELAY_DRIVE_REG		0x0d
     67  1.1.10.1  perseant #define	 YT8511_FE_TX_CLK_DELAY_SEL	__BITS(15,12)
     68  1.1.10.1  perseant 
     69  1.1.10.1  perseant #define	YT8521_CLOCK_GATING_REG		0x0c
     70  1.1.10.1  perseant #define	 YT8521_RX_CLK_EN		__BIT(12)
     71  1.1.10.1  perseant 
     72  1.1.10.1  perseant #define	YT8511_SLEEP_CONTROL1_REG	0x27
     73  1.1.10.1  perseant #define	 YT8511_PLLON_IN_SLP		__BIT(14)
     74  1.1.10.1  perseant 
     75  1.1.10.1  perseant #define	YT8521_SLEEP_CONTROL1_REG	0x27
     76  1.1.10.1  perseant #define	 YT8521_PLLON_IN_SLP		__BIT(14)
     77  1.1.10.1  perseant 
     78  1.1.10.1  perseant #define YT8521_EXT_CHIP_CONFIG		0xa001
     79  1.1.10.1  perseant #define  YT8521_RXC_DLY_EN		__BIT(8)
     80  1.1.10.1  perseant #define  YT8521_CFG_LDO_MASK		__BITS(5, 4)
     81  1.1.10.1  perseant #define   YT8521_CFG_LDO_3V3		0
     82  1.1.10.1  perseant #define   YT8521_CFG_LDO_2V5		1
     83  1.1.10.1  perseant #define   YT8521_CFG_LDO_1V8		2	/* or 3 */
     84  1.1.10.1  perseant 
     85  1.1.10.1  perseant #define YT8521_EXT_SDS_CONFIG		0xa002
     86  1.1.10.1  perseant 
     87  1.1.10.1  perseant #define YT8521_EXT_RGMII_CONFIG1	0xa003
     88  1.1.10.1  perseant #define  YT8521_TX_CLK_SEL_INV		__BIT(14)
     89  1.1.10.1  perseant #define  YT8521_RX_DELAY_SEL_MASK	__BITS(13, 10)
     90  1.1.10.1  perseant #define  YT8521_FE_TX_DELAY_SEL_MASK	__BITS(7, 4)
     91  1.1.10.1  perseant #define  YT8521_GE_TX_DELAY_SEL_MASK	__BITS(3, 0)
     92  1.1.10.1  perseant #define  YT8521_DELAY_PS(ps)		((ps) / 150)
     93  1.1.10.1  perseant #define YT8521_DELAY_DEFAULT		1950
     94  1.1.10.1  perseant 
     95  1.1.10.1  perseant #define YT8521_EXT_RGMII_CONFIG2	0xa004
     96  1.1.10.1  perseant 
     97  1.1.10.1  perseant #define YT8521_EXT_PAD_DRIVE_STRENGTH	0xa010
     98  1.1.10.1  perseant #define  YT8531_RGMII_RXC_DS_MASK	__BITS(15, 13)
     99  1.1.10.1  perseant #define  YT8531_RGMII_RXD_DS_HIMASK	__BIT(12)
    100  1.1.10.1  perseant #define  YT8531_RGMII_RXD_DS_LOMASK	__BITS(5, 4)
    101  1.1.10.1  perseant #define YT8531_RGMII_RXD_DS_MASK \
    102  1.1.10.1  perseant     (YT8531_RGMII_RXD_DS_HIMASK | YT8531_RGMII_RXD_DS_LOMASK)
    103  1.1.10.1  perseant 
    104  1.1.10.1  perseant #define YT8531_RGMII_RXD_DS_HIBITS	__BIT(2)
    105  1.1.10.1  perseant #define YT8531_RGMII_RXD_DS_LOBITS	__BITS(1, 0)
    106  1.1.10.1  perseant 
    107  1.1.10.1  perseant CTASSERT(__SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_HIMASK) ==
    108  1.1.10.1  perseant 	 __SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_HIBITS));
    109  1.1.10.1  perseant CTASSERT(__SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_LOMASK) ==
    110  1.1.10.1  perseant 	 __SHIFTOUT_MASK(YT8531_RGMII_RXD_DS_LOBITS));
    111  1.1.10.1  perseant 
    112  1.1.10.1  perseant #define YT8531_DEFAULT_DS		3
    113  1.1.10.1  perseant 
    114  1.1.10.1  perseant #define YT8521_EXT_SYNCE_CFG		0xa012
    115  1.1.10.1  perseant #define  YT8531_EN_SYNC_E		__BIT(6)
    116  1.1.10.1  perseant #define  YT8531_CLK_FRE_SEL_125M	__BIT(4)
    117  1.1.10.1  perseant #define  YT8531_CLK_SRC_SEL_MASK	__BITS(3, 1)
    118  1.1.10.1  perseant #define   YT8531_CLK_SRC_SEL_PLL_125M	0
    119  1.1.10.1  perseant #define   YT8531_CLK_SRC_SEL_REF_25M	4
    120  1.1.10.1  perseant 
    121  1.1.10.1  perseant 
    122  1.1.10.1  perseant typedef enum mcommtype {
    123  1.1.10.1  perseant     YTUNK,
    124  1.1.10.1  perseant     YT8511,
    125  1.1.10.1  perseant     YT8521,
    126  1.1.10.1  perseant     YT8531,
    127  1.1.10.1  perseant } mcommtype_t;
    128  1.1.10.1  perseant 
    129  1.1.10.1  perseant struct mcomm_softc {
    130  1.1.10.1  perseant 	struct mii_softc	sc_miisc;
    131  1.1.10.1  perseant 
    132  1.1.10.1  perseant 	mcommtype_t		sc_type;
    133  1.1.10.1  perseant 
    134  1.1.10.1  perseant 	bool			sc_tx_clk_adj_enabled;
    135  1.1.10.1  perseant 	bool			sc_tx_clk_10_inverted;
    136  1.1.10.1  perseant 	bool			sc_tx_clk_100_inverted;
    137  1.1.10.1  perseant 	bool			sc_tx_clk_1000_inverted;
    138  1.1.10.1  perseant 	u_int			sc_clk_out_frequency_hz;
    139  1.1.10.1  perseant 	u_int			sc_rx_clk_drv_microamp;
    140  1.1.10.1  perseant 	u_int			sc_rx_data_drv_microamp;
    141  1.1.10.1  perseant 	u_int			sc_rx_internal_delay_ps;
    142  1.1.10.1  perseant 	u_int			sc_tx_internal_delay_ps;
    143  1.1.10.1  perseant };
    144       1.1  jmcneill 
    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.1.10.1  perseant 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.1.10.1  perseant 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.1.10.1  perseant 	.pf_service = mcommphy_service,
    156  1.1.10.1  perseant 	.pf_status = ukphy_status,
    157  1.1.10.1  perseant 	.pf_reset = mcommphy_reset,
    158       1.1  jmcneill };
    159       1.1  jmcneill 
    160  1.1.10.1  perseant static const struct mii_phydesc mcommphys[] = {
    161  1.1.10.1  perseant 	MII_PHY_DESC(MOTORCOMM, YT8531),
    162  1.1.10.1  perseant 	MII_PHY_END,
    163  1.1.10.1  perseant };
    164  1.1.10.1  perseant 
    165  1.1.10.1  perseant static void
    166  1.1.10.1  perseant mcomm_yt8531properties(struct mcomm_softc *msc, prop_dictionary_t dict)
    167  1.1.10.1  perseant {
    168  1.1.10.1  perseant 	struct mii_softc * const sc = &msc->sc_miisc;
    169  1.1.10.1  perseant 
    170  1.1.10.1  perseant 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-adj-enabled",
    171  1.1.10.1  perseant 	    &msc->sc_tx_clk_adj_enabled)) {
    172  1.1.10.1  perseant 		msc->sc_tx_clk_adj_enabled = false;
    173  1.1.10.1  perseant 	} else {
    174  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    175  1.1.10.1  perseant 		    "motorcomm,tx-clk-adj-enabled is %s\n",
    176  1.1.10.1  perseant 		    msc->sc_tx_clk_adj_enabled ? "true" : "false");
    177  1.1.10.1  perseant 	}
    178  1.1.10.1  perseant 
    179  1.1.10.1  perseant 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-10-inverted",
    180  1.1.10.1  perseant 	    &msc->sc_tx_clk_10_inverted)) {
    181  1.1.10.1  perseant 		msc->sc_tx_clk_10_inverted = false;
    182  1.1.10.1  perseant 	} else {
    183  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    184  1.1.10.1  perseant 		    "motorcomm,tx_clk_10_inverted is %s\n",
    185  1.1.10.1  perseant 		    msc->sc_tx_clk_10_inverted ? "true" : "false");
    186  1.1.10.1  perseant 	}
    187  1.1.10.1  perseant 
    188  1.1.10.1  perseant 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-100-inverted",
    189  1.1.10.1  perseant 	    &msc->sc_tx_clk_100_inverted)) {
    190  1.1.10.1  perseant 		msc->sc_tx_clk_100_inverted = false;
    191  1.1.10.1  perseant 	} else {
    192  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    193  1.1.10.1  perseant 		    "motorcomm,tx-clk-100-inverted is %s\n",
    194  1.1.10.1  perseant 		    msc->sc_tx_clk_100_inverted ? "true" : "false");
    195  1.1.10.1  perseant 	}
    196  1.1.10.1  perseant 
    197  1.1.10.1  perseant 	if (!prop_dictionary_get_bool(dict, "motorcomm,tx-clk-1000-inverted",
    198  1.1.10.1  perseant 	    &msc->sc_tx_clk_1000_inverted)) {
    199  1.1.10.1  perseant 		msc->sc_tx_clk_1000_inverted = false;
    200  1.1.10.1  perseant 	} else {
    201  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    202  1.1.10.1  perseant 		    "motorcomm,tx-clk-1000-inverted is %s\n",
    203  1.1.10.1  perseant 		    msc->sc_tx_clk_1000_inverted ? "true" : "false");
    204  1.1.10.1  perseant 	}
    205  1.1.10.1  perseant 
    206  1.1.10.1  perseant 	if (!prop_dictionary_get_uint32(dict, "motorcomm,clk-out-frequency-hz",
    207  1.1.10.1  perseant 	    &msc->sc_clk_out_frequency_hz)) {
    208  1.1.10.1  perseant 		msc->sc_clk_out_frequency_hz = 0;
    209  1.1.10.1  perseant 	} else {
    210  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    211  1.1.10.1  perseant 		    "motorcomm,clk-out-frequency-hz is %u\n",
    212  1.1.10.1  perseant 		    msc->sc_clk_out_frequency_hz);
    213  1.1.10.1  perseant 	}
    214  1.1.10.1  perseant 
    215  1.1.10.1  perseant 	if (!prop_dictionary_get_uint32(dict, "motorcomm,rx-clk-drv-microamp",
    216  1.1.10.1  perseant 	    &msc->sc_rx_clk_drv_microamp)) {
    217  1.1.10.1  perseant 		aprint_debug_dev(sc->mii_dev,
    218  1.1.10.1  perseant 		    "motorcomm,rx-clk-drv-microamp not found\n");
    219  1.1.10.1  perseant 	} else {
    220  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    221  1.1.10.1  perseant 		    "rx-clk-drv-microamp is %u\n",
    222  1.1.10.1  perseant 		    msc->sc_rx_clk_drv_microamp);
    223  1.1.10.1  perseant 	}
    224  1.1.10.1  perseant 
    225  1.1.10.1  perseant 	if (!prop_dictionary_get_uint32(dict, "motorcomm,rx-data-drv-microamp",
    226  1.1.10.1  perseant 	    &msc->sc_rx_data_drv_microamp)) {
    227  1.1.10.1  perseant 		aprint_debug_dev(sc->mii_dev,
    228  1.1.10.1  perseant 		    "motorcomm,rx-data-drv-microamp not found\n");
    229  1.1.10.1  perseant 	} else {
    230  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    231  1.1.10.1  perseant 		    "motorcomm,rx-data-drv-microamp is %u\n",
    232  1.1.10.1  perseant 		    msc->sc_rx_data_drv_microamp);
    233  1.1.10.1  perseant 	}
    234  1.1.10.1  perseant 
    235  1.1.10.1  perseant 	if (!prop_dictionary_get_uint32(dict, "rx-internal-delay-ps",
    236  1.1.10.1  perseant 	    &msc->sc_rx_internal_delay_ps)) {
    237  1.1.10.1  perseant 		aprint_debug_dev(sc->mii_dev,
    238  1.1.10.1  perseant 		    "rx-internal-delay-ps not found\n");
    239  1.1.10.1  perseant 	} else {
    240  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    241  1.1.10.1  perseant 		    "rx-internal-delay-ps is %u\n",
    242  1.1.10.1  perseant 		    msc->sc_rx_internal_delay_ps);
    243  1.1.10.1  perseant 	}
    244  1.1.10.1  perseant 
    245  1.1.10.1  perseant 	if (!prop_dictionary_get_uint32(dict, "tx-internal-delay-ps",
    246  1.1.10.1  perseant 	    &msc->sc_tx_internal_delay_ps)) {
    247  1.1.10.1  perseant 		aprint_debug_dev(sc->mii_dev,
    248  1.1.10.1  perseant 		    "tx-internal-delay-ps not found\n");
    249  1.1.10.1  perseant 	} else {
    250  1.1.10.1  perseant 		aprint_verbose_dev(sc->mii_dev,
    251  1.1.10.1  perseant 		    "tx-internal-delay-ps is %u\n",
    252  1.1.10.1  perseant 		    msc->sc_tx_internal_delay_ps);
    253  1.1.10.1  perseant 	}
    254  1.1.10.1  perseant }
    255  1.1.10.1  perseant 
    256  1.1.10.1  perseant static bool
    257  1.1.10.1  perseant 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.1.10.1  perseant 	if (MII_OUI(ma->mii_id1, ma->mii_id2) == YT85X1_MCOMMPHY_OUI &&
    265  1.1.10.1  perseant 	    MII_MODEL(ma->mii_id2) == YT8511_MCOMMPHY_MODEL &&
    266  1.1.10.1  perseant 	    MII_REV(ma->mii_id2) == YT85X1_MCOMMPHY_REV) {
    267  1.1.10.1  perseant 		return true;
    268       1.1  jmcneill 	}
    269  1.1.10.1  perseant 	return false;
    270  1.1.10.1  perseant }
    271  1.1.10.1  perseant 
    272  1.1.10.1  perseant 
    273  1.1.10.1  perseant static int
    274  1.1.10.1  perseant mcommphymatch(device_t parent, cfdata_t match, void *aux)
    275  1.1.10.1  perseant {
    276  1.1.10.1  perseant 	struct mii_attach_args *ma = aux;
    277  1.1.10.1  perseant 
    278  1.1.10.1  perseant 	if (mii_phy_match(ma, mcommphys) != NULL)
    279  1.1.10.1  perseant 		return 10;
    280  1.1.10.1  perseant 
    281  1.1.10.1  perseant 	if (mcommphy_isyt8511(ma))
    282  1.1.10.1  perseant 		return 10;
    283       1.1  jmcneill 
    284       1.1  jmcneill 	return 0;
    285       1.1  jmcneill }
    286       1.1  jmcneill 
    287       1.1  jmcneill static void
    288  1.1.10.1  perseant mcomm_yt8511_init(struct mcomm_softc *msc)
    289  1.1.10.1  perseant {
    290  1.1.10.1  perseant 	struct mii_softc *sc = &msc->sc_miisc;
    291  1.1.10.1  perseant 	uint16_t oldaddr, data;
    292  1.1.10.1  perseant 
    293  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    294  1.1.10.1  perseant 
    295  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8511_CLOCK_GATING_REG);
    296  1.1.10.1  perseant 
    297  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    298  1.1.10.1  perseant 
    299  1.1.10.1  perseant 	data &= ~YT8511_CLK_25M_SEL;
    300  1.1.10.1  perseant 	data |= __SHIFTIN(YT8511_CLK_25M_SEL_125M, YT8511_CLK_25M_SEL);
    301  1.1.10.1  perseant 	if (ISSET(sc->mii_flags, MIIF_RXID)) {
    302  1.1.10.1  perseant 		data |= YT8511_RX_CLK_DELAY_EN;
    303  1.1.10.1  perseant 	} else {
    304  1.1.10.1  perseant 		data &= ~YT8511_RX_CLK_DELAY_EN;
    305  1.1.10.1  perseant 	}
    306  1.1.10.1  perseant 	data &= ~YT8511_TX_CLK_DELAY_SEL;
    307  1.1.10.1  perseant 	if (ISSET(sc->mii_flags, MIIF_TXID)) {
    308  1.1.10.1  perseant 		data |= __SHIFTIN(0xf, YT8511_TX_CLK_DELAY_SEL);
    309  1.1.10.1  perseant 	} else {
    310  1.1.10.1  perseant 		data |= __SHIFTIN(0x2, YT8511_TX_CLK_DELAY_SEL);
    311  1.1.10.1  perseant 	}
    312  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    313  1.1.10.1  perseant 
    314  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8511_SLEEP_CONTROL1_REG);
    315  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    316  1.1.10.1  perseant 
    317  1.1.10.1  perseant 	data |= YT8511_PLLON_IN_SLP;
    318  1.1.10.1  perseant 
    319  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    320  1.1.10.1  perseant 
    321  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    322  1.1.10.1  perseant }
    323  1.1.10.1  perseant 
    324  1.1.10.1  perseant 
    325  1.1.10.1  perseant 
    326  1.1.10.1  perseant static void
    327  1.1.10.1  perseant mcomm_yt8521_init(struct mcomm_softc *msc)
    328  1.1.10.1  perseant {
    329  1.1.10.1  perseant 	struct mii_softc *sc = &msc->sc_miisc;
    330  1.1.10.1  perseant 	bool rx_delay_en = false;
    331  1.1.10.1  perseant 	u_int rx_delay_val;
    332  1.1.10.1  perseant 	u_int tx_delay_val;
    333  1.1.10.1  perseant 	uint16_t oldaddr, data;
    334  1.1.10.1  perseant 
    335  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    336  1.1.10.1  perseant 
    337  1.1.10.1  perseant 	u_int rx_delay = msc->sc_rx_internal_delay_ps;
    338  1.1.10.1  perseant 	if (rx_delay <= 15 * 150 && rx_delay % 150 == 0) {
    339  1.1.10.1  perseant 		rx_delay_val = YT8521_DELAY_PS(rx_delay);
    340  1.1.10.1  perseant 	} else {
    341  1.1.10.1  perseant 		/* It's OK if this underflows */
    342  1.1.10.1  perseant 		rx_delay -= 1900;
    343  1.1.10.1  perseant 		if (rx_delay <= 15 * 150 && rx_delay % 150 == 0) {
    344  1.1.10.1  perseant 			rx_delay_en = true;
    345  1.1.10.1  perseant 			rx_delay_val = YT8521_DELAY_PS(rx_delay);
    346  1.1.10.1  perseant 		} else {
    347  1.1.10.1  perseant 			rx_delay_val = YT8521_DELAY_PS(YT8521_DELAY_DEFAULT);
    348  1.1.10.1  perseant 		}
    349  1.1.10.1  perseant 	}
    350  1.1.10.1  perseant 
    351  1.1.10.1  perseant 	u_int tx_delay = msc->sc_tx_internal_delay_ps;
    352  1.1.10.1  perseant 	if (tx_delay <= 15 * 150 && tx_delay % 150 == 0) {
    353  1.1.10.1  perseant 		tx_delay_val = YT8521_DELAY_PS(tx_delay);
    354  1.1.10.1  perseant 	} else {
    355  1.1.10.1  perseant 		tx_delay_val = YT8521_DELAY_PS(YT8521_DELAY_DEFAULT);
    356  1.1.10.1  perseant 	}
    357  1.1.10.1  perseant 
    358  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_CHIP_CONFIG);
    359  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    360  1.1.10.1  perseant 
    361  1.1.10.1  perseant 	if (rx_delay_en)
    362  1.1.10.1  perseant 		data |= YT8521_RXC_DLY_EN;
    363  1.1.10.1  perseant 	else
    364  1.1.10.1  perseant 		data &= ~YT8521_RXC_DLY_EN;
    365  1.1.10.1  perseant 
    366  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    367  1.1.10.1  perseant 
    368  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
    369  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    370  1.1.10.1  perseant 
    371  1.1.10.1  perseant 	data &= ~(YT8521_RX_DELAY_SEL_MASK | YT8521_GE_TX_DELAY_SEL_MASK);
    372  1.1.10.1  perseant 	// XXX FE?
    373  1.1.10.1  perseant 	data |=
    374  1.1.10.1  perseant 	    __SHIFTIN(rx_delay_val, YT8521_RX_DELAY_SEL_MASK) |
    375  1.1.10.1  perseant 	    __SHIFTIN(tx_delay_val, YT8521_GE_TX_DELAY_SEL_MASK);
    376  1.1.10.1  perseant 
    377  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    378  1.1.10.1  perseant 
    379  1.1.10.1  perseant 	/* Restore address register. */
    380  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    381  1.1.10.1  perseant }
    382  1.1.10.1  perseant 
    383  1.1.10.1  perseant struct mcomm_ytphy_ds_map {
    384  1.1.10.1  perseant 	u_int microamps;
    385  1.1.10.1  perseant 	u_int ds;
    386  1.1.10.1  perseant };
    387  1.1.10.1  perseant 
    388  1.1.10.1  perseant struct mcomm_ytphy_ds_map mcomm_1d8v_ds_map[] = {
    389  1.1.10.1  perseant 	{ .microamps = 1200, .ds = 0 },
    390  1.1.10.1  perseant 	{ .microamps = 2100, .ds = 1 },
    391  1.1.10.1  perseant 	{ .microamps = 2700, .ds = 2 },
    392  1.1.10.1  perseant 	{ .microamps = 2910, .ds = 3 },
    393  1.1.10.1  perseant 	{ .microamps = 3110, .ds = 4 },
    394  1.1.10.1  perseant 	{ .microamps = 3600, .ds = 5 },
    395  1.1.10.1  perseant 	{ .microamps = 3970, .ds = 6 },
    396  1.1.10.1  perseant 	{ .microamps = 4350, .ds = 7 },
    397  1.1.10.1  perseant };
    398  1.1.10.1  perseant struct mcomm_ytphy_ds_map mcomm_3d3v_ds_map[] = {
    399  1.1.10.1  perseant 	{ .microamps = 3070, .ds = 0 },
    400  1.1.10.1  perseant 	{ .microamps = 4080, .ds = 1 },
    401  1.1.10.1  perseant 	{ .microamps = 4370, .ds = 2 },
    402  1.1.10.1  perseant 	{ .microamps = 4680, .ds = 3 },
    403  1.1.10.1  perseant 	{ .microamps = 5020, .ds = 4 },
    404  1.1.10.1  perseant 	{ .microamps = 5450, .ds = 5 },
    405  1.1.10.1  perseant 	{ .microamps = 5740, .ds = 6 },
    406  1.1.10.1  perseant 	{ .microamps = 6140, .ds = 7 },
    407  1.1.10.1  perseant };
    408  1.1.10.1  perseant 
    409  1.1.10.1  perseant static u_int
    410  1.1.10.1  perseant mcomm_yt8531_ds(struct mcomm_softc *msc,
    411  1.1.10.1  perseant     struct mcomm_ytphy_ds_map *ds_map, size_t n,
    412  1.1.10.1  perseant     u_int microamps, u_int millivolts)
    413  1.1.10.1  perseant {
    414  1.1.10.1  perseant 	for (size_t i = 0; i < n; i++) {
    415  1.1.10.1  perseant 		if (ds_map[i].microamps == microamps)
    416  1.1.10.1  perseant 			return ds_map[i].ds;
    417  1.1.10.1  perseant 	}
    418  1.1.10.1  perseant 	if (microamps) {
    419  1.1.10.1  perseant 		struct mii_softc *sc = &msc->sc_miisc;
    420  1.1.10.1  perseant 
    421  1.1.10.1  perseant 		aprint_error_dev(sc->mii_dev, "unknown drive strength "
    422  1.1.10.1  perseant 		    "(%u uA at %u mV)", microamps, millivolts);
    423  1.1.10.1  perseant 	}
    424  1.1.10.1  perseant 	return YT8531_DEFAULT_DS;
    425  1.1.10.1  perseant }
    426  1.1.10.1  perseant 
    427  1.1.10.1  perseant static void
    428  1.1.10.1  perseant mcomm_yt8531_init(struct mcomm_softc *msc)
    429  1.1.10.1  perseant {
    430  1.1.10.1  perseant 	struct mii_softc *sc = &msc->sc_miisc;
    431  1.1.10.1  perseant 	uint16_t oldaddr, data;
    432  1.1.10.1  perseant 
    433  1.1.10.1  perseant 	mcomm_yt8521_init(msc);
    434  1.1.10.1  perseant 
    435  1.1.10.1  perseant 	/* Save address register. */
    436  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    437  1.1.10.1  perseant 
    438  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_CHIP_CONFIG);
    439  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    440  1.1.10.1  perseant 
    441  1.1.10.1  perseant 	struct mcomm_ytphy_ds_map *ds_map = NULL;
    442  1.1.10.1  perseant 	size_t ds_mapsize;
    443  1.1.10.1  perseant 	u_int millivolts = 1800;
    444  1.1.10.1  perseant 	switch (__SHIFTOUT(data, YT8521_CFG_LDO_MASK)) {
    445  1.1.10.1  perseant 	case YT8521_CFG_LDO_3V3:
    446  1.1.10.1  perseant 		ds_map = mcomm_3d3v_ds_map;
    447  1.1.10.1  perseant 		ds_mapsize = __arraycount(mcomm_3d3v_ds_map);
    448  1.1.10.1  perseant 		millivolts = 3300;
    449  1.1.10.1  perseant 		break;
    450  1.1.10.1  perseant 	case YT8521_CFG_LDO_2V5:
    451  1.1.10.1  perseant 		millivolts = 2500;
    452  1.1.10.1  perseant 		break;
    453  1.1.10.1  perseant 	default:
    454  1.1.10.1  perseant 		ds_map = mcomm_1d8v_ds_map;
    455  1.1.10.1  perseant 		ds_mapsize = __arraycount(mcomm_1d8v_ds_map);
    456  1.1.10.1  perseant 		break;
    457  1.1.10.1  perseant 	}
    458  1.1.10.1  perseant 
    459  1.1.10.1  perseant 	if (ds_map) {
    460  1.1.10.1  perseant 		u_int rx_clk_ds = mcomm_yt8531_ds(msc, ds_map, ds_mapsize,
    461  1.1.10.1  perseant 		    msc->sc_rx_clk_drv_microamp, millivolts);
    462  1.1.10.1  perseant 		u_int rx_data_ds = mcomm_yt8531_ds(msc, ds_map, ds_mapsize,
    463  1.1.10.1  perseant 		    msc->sc_rx_data_drv_microamp, millivolts);
    464  1.1.10.1  perseant 
    465  1.1.10.1  perseant 		PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_PAD_DRIVE_STRENGTH);
    466  1.1.10.1  perseant 		PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    467  1.1.10.1  perseant 
    468  1.1.10.1  perseant 		data &= ~(YT8531_RGMII_RXC_DS_MASK | YT8531_RGMII_RXD_DS_MASK);
    469  1.1.10.1  perseant 
    470  1.1.10.1  perseant 		u_int rx_data_ds_hi =
    471  1.1.10.1  perseant 		    __SHIFTOUT(rx_data_ds, YT8531_RGMII_RXD_DS_HIBITS);
    472  1.1.10.1  perseant 		u_int rx_data_ds_lo =
    473  1.1.10.1  perseant 		    __SHIFTOUT(rx_data_ds, YT8531_RGMII_RXD_DS_LOBITS);
    474  1.1.10.1  perseant 		data |=
    475  1.1.10.1  perseant 		    __SHIFTIN(rx_clk_ds, YT8531_RGMII_RXC_DS_MASK) |
    476  1.1.10.1  perseant 		    __SHIFTIN(rx_data_ds_hi, YT8531_RGMII_RXD_DS_HIMASK) |
    477  1.1.10.1  perseant 		    __SHIFTIN(rx_data_ds_lo, YT8531_RGMII_RXD_DS_LOMASK);
    478  1.1.10.1  perseant 
    479  1.1.10.1  perseant 		PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    480  1.1.10.1  perseant 	}
    481  1.1.10.1  perseant 
    482  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_SYNCE_CFG);
    483  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    484  1.1.10.1  perseant 
    485  1.1.10.1  perseant 	data &= ~(YT8531_EN_SYNC_E | YT8531_CLK_SRC_SEL_MASK);
    486  1.1.10.1  perseant 
    487  1.1.10.1  perseant 	switch (msc->sc_clk_out_frequency_hz) {
    488  1.1.10.1  perseant 	case 125000000:
    489  1.1.10.1  perseant 		data |= YT8531_EN_SYNC_E;
    490  1.1.10.1  perseant 		data |= YT8531_CLK_FRE_SEL_125M;
    491  1.1.10.1  perseant 		data |= __SHIFTIN(YT8531_CLK_SRC_SEL_PLL_125M, YT8531_CLK_SRC_SEL_MASK);
    492  1.1.10.1  perseant 		break;
    493  1.1.10.1  perseant 	case 25000000:
    494  1.1.10.1  perseant 		data |= YT8531_EN_SYNC_E;
    495  1.1.10.1  perseant 		data |= __SHIFTIN(YT8531_CLK_SRC_SEL_REF_25M, YT8531_CLK_SRC_SEL_MASK);
    496  1.1.10.1  perseant 		break;
    497  1.1.10.1  perseant 	default:
    498  1.1.10.1  perseant 		break;
    499  1.1.10.1  perseant 	}
    500  1.1.10.1  perseant 
    501  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    502  1.1.10.1  perseant 
    503  1.1.10.1  perseant 	/* Restore address register. */
    504  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    505  1.1.10.1  perseant }
    506  1.1.10.1  perseant 
    507  1.1.10.1  perseant 
    508  1.1.10.1  perseant static void
    509  1.1.10.1  perseant mcommphy_reset(struct mii_softc *sc)
    510  1.1.10.1  perseant {
    511  1.1.10.1  perseant 	struct mcomm_softc * const msc =
    512  1.1.10.1  perseant 	    container_of(sc, struct mcomm_softc, sc_miisc);
    513  1.1.10.1  perseant 
    514  1.1.10.1  perseant 	KASSERT(mii_locked(sc->mii_pdata));
    515  1.1.10.1  perseant 
    516  1.1.10.1  perseant 	mii_phy_reset(sc);
    517  1.1.10.1  perseant 
    518  1.1.10.1  perseant 	switch (msc->sc_type) {
    519  1.1.10.1  perseant 	case YT8511:
    520  1.1.10.1  perseant 		mcomm_yt8511_init(msc);
    521  1.1.10.1  perseant 		break;
    522  1.1.10.1  perseant 	case YT8531:
    523  1.1.10.1  perseant 		mcomm_yt8531_init(msc);
    524  1.1.10.1  perseant 		break;
    525  1.1.10.1  perseant 	default:
    526  1.1.10.1  perseant 		return;
    527  1.1.10.1  perseant 	}
    528  1.1.10.1  perseant }
    529  1.1.10.1  perseant 
    530  1.1.10.1  perseant 
    531  1.1.10.1  perseant static void
    532       1.1  jmcneill mcommphyattach(device_t parent, device_t self, void *aux)
    533       1.1  jmcneill {
    534  1.1.10.1  perseant 	struct mcomm_softc *msc = device_private(self);
    535  1.1.10.1  perseant 	struct mii_softc *sc = &msc->sc_miisc;
    536       1.1  jmcneill 	struct mii_attach_args *ma = aux;
    537       1.1  jmcneill 	struct mii_data *mii = ma->mii_data;
    538       1.1  jmcneill 
    539  1.1.10.1  perseant 	msc->sc_type = YTUNK;
    540  1.1.10.1  perseant 	if (mcommphy_isyt8511(ma)) {
    541  1.1.10.1  perseant 		msc->sc_type = YT8511;
    542  1.1.10.1  perseant 		aprint_normal(": Motorcomm YT8511 GbE PHY\n");
    543  1.1.10.1  perseant 	} else {
    544  1.1.10.1  perseant 		KASSERT(mii_phy_match(ma, mcommphys) != NULL);
    545  1.1.10.1  perseant 		msc->sc_type = YT8531;
    546  1.1.10.1  perseant 		aprint_normal(": Motorcomm YT8531 GbE PHY\n");
    547  1.1.10.1  perseant 	}
    548       1.1  jmcneill 	aprint_naive(": Media interface\n");
    549       1.1  jmcneill 
    550       1.1  jmcneill 	sc->mii_dev = self;
    551       1.1  jmcneill 	sc->mii_inst = mii->mii_instance;
    552       1.1  jmcneill 	sc->mii_phy = ma->mii_phyno;
    553       1.1  jmcneill 	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
    554       1.1  jmcneill 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
    555       1.1  jmcneill 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
    556       1.1  jmcneill 	sc->mii_funcs = &mcommphy_funcs;
    557       1.1  jmcneill 	sc->mii_pdata = mii;
    558       1.1  jmcneill 	sc->mii_flags = ma->mii_flags;
    559       1.1  jmcneill 
    560  1.1.10.1  perseant 	prop_dictionary_t dict = device_properties(parent);
    561  1.1.10.1  perseant 	switch (msc->sc_type) {
    562  1.1.10.1  perseant 	case YT8521:
    563  1.1.10.1  perseant 	case YT8531:
    564  1.1.10.1  perseant 		/* Default values */
    565  1.1.10.1  perseant 		msc->sc_rx_internal_delay_ps = YT8521_DELAY_DEFAULT;
    566  1.1.10.1  perseant 		msc->sc_tx_internal_delay_ps = YT8521_DELAY_DEFAULT;
    567       1.1  jmcneill 
    568  1.1.10.1  perseant 		mcomm_yt8531properties(msc, dict);
    569  1.1.10.1  perseant 		break;
    570  1.1.10.1  perseant 	default:
    571  1.1.10.1  perseant 		break;
    572       1.1  jmcneill 	}
    573       1.1  jmcneill 
    574  1.1.10.1  perseant 	mii_lock(mii);
    575       1.1  jmcneill 
    576  1.1.10.1  perseant 	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.1.10.1  perseant static void
    589  1.1.10.1  perseant ytphy_yt8521_update(struct mcomm_softc *msc)
    590  1.1.10.1  perseant {
    591  1.1.10.1  perseant 	struct mii_softc *sc = &msc->sc_miisc;
    592  1.1.10.1  perseant 	struct mii_data *mii = sc->mii_pdata;
    593  1.1.10.1  perseant 	bool tx_clk_inv = false;
    594  1.1.10.1  perseant 	uint16_t oldaddr, data;
    595  1.1.10.1  perseant 
    596  1.1.10.1  perseant 	if (sc->mii_media_active == mii->mii_media_active)
    597  1.1.10.1  perseant 		return;
    598  1.1.10.1  perseant 
    599  1.1.10.1  perseant 	if (!msc->sc_tx_clk_adj_enabled)
    600  1.1.10.1  perseant 		return;
    601  1.1.10.1  perseant 
    602  1.1.10.1  perseant 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
    603  1.1.10.1  perseant 	case IFM_1000_T:
    604  1.1.10.1  perseant 		tx_clk_inv = msc->sc_tx_clk_1000_inverted;
    605  1.1.10.1  perseant 		break;
    606  1.1.10.1  perseant 	case IFM_100_TX:
    607  1.1.10.1  perseant 		tx_clk_inv = msc->sc_tx_clk_100_inverted;
    608  1.1.10.1  perseant 		break;
    609  1.1.10.1  perseant 	case IFM_10_T:
    610  1.1.10.1  perseant 		tx_clk_inv = msc->sc_tx_clk_10_inverted;
    611  1.1.10.1  perseant 		break;
    612  1.1.10.1  perseant 	}
    613  1.1.10.1  perseant 
    614  1.1.10.1  perseant 	/* Save address register. */
    615  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_ADDR, &oldaddr);
    616  1.1.10.1  perseant 
    617  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, YT8521_EXT_RGMII_CONFIG1);
    618  1.1.10.1  perseant 	PHY_READ(sc, YTPHY_EXT_REG_DATA, &data);
    619  1.1.10.1  perseant 
    620  1.1.10.1  perseant 	if (tx_clk_inv)
    621  1.1.10.1  perseant 		data |= YT8521_TX_CLK_SEL_INV;
    622  1.1.10.1  perseant 	else
    623  1.1.10.1  perseant 		data &= ~YT8521_TX_CLK_SEL_INV;
    624  1.1.10.1  perseant 
    625  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_DATA, data);
    626  1.1.10.1  perseant 
    627  1.1.10.1  perseant 	/* Restore address register. */
    628  1.1.10.1  perseant 	PHY_WRITE(sc, YTPHY_EXT_REG_ADDR, oldaddr);
    629  1.1.10.1  perseant }
    630  1.1.10.1  perseant 
    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.1.10.1  perseant 	struct mcomm_softc * const msc =
    636  1.1.10.1  perseant 	    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.1.10.1  perseant 	if (msc->sc_type != YT8511)
    674  1.1.10.1  perseant 		ytphy_yt8521_update(msc);
    675  1.1.10.1  perseant 
    676       1.1  jmcneill 	mii_phy_update(sc, cmd);
    677       1.1  jmcneill 	return 0;
    678       1.1  jmcneill }
    679