Home | History | Annotate | Line # | Download | only in mii
      1  1.37   msaitoh /*	$NetBSD: igphy.c,v 1.37 2020/11/04 09:15:10 msaitoh Exp $	*/
      2   1.1      fvdl 
      3   1.1      fvdl /*
      4   1.1      fvdl  * The Intel copyright applies to the analog register setup, and the
      5  1.27   msaitoh  * SmartSpeed workaround code.
      6   1.1      fvdl  */
      7   1.1      fvdl 
      8   1.1      fvdl /*******************************************************************************
      9   1.1      fvdl 
     10   1.1      fvdl   Copyright (c) 2001-2003, Intel Corporation
     11   1.1      fvdl   All rights reserved.
     12   1.1      fvdl 
     13   1.1      fvdl   Redistribution and use in source and binary forms, with or without
     14   1.1      fvdl   modification, are permitted provided that the following conditions are met:
     15   1.1      fvdl 
     16   1.1      fvdl    1. Redistributions of source code must retain the above copyright notice,
     17   1.1      fvdl       this list of conditions and the following disclaimer.
     18   1.1      fvdl 
     19   1.1      fvdl    2. Redistributions in binary form must reproduce the above copyright
     20   1.1      fvdl       notice, this list of conditions and the following disclaimer in the
     21   1.1      fvdl       documentation and/or other materials provided with the distribution.
     22   1.1      fvdl 
     23   1.1      fvdl    3. Neither the name of the Intel Corporation nor the names of its
     24   1.1      fvdl       contributors may be used to endorse or promote products derived from
     25   1.1      fvdl       this software without specific prior written permission.
     26   1.1      fvdl 
     27   1.1      fvdl   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     28   1.1      fvdl   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29   1.1      fvdl   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30   1.1      fvdl   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     31   1.1      fvdl   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32   1.1      fvdl   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33   1.1      fvdl   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34   1.1      fvdl   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35   1.1      fvdl   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36   1.1      fvdl   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37   1.1      fvdl   POSSIBILITY OF SUCH DAMAGE.
     38   1.1      fvdl 
     39   1.1      fvdl *******************************************************************************/
     40   1.1      fvdl 
     41   1.1      fvdl 
     42   1.1      fvdl /*-
     43   1.1      fvdl  * Copyright (c) 1998, 1999, 2000, 2003 The NetBSD Foundation, Inc.
     44   1.1      fvdl  * All rights reserved.
     45   1.1      fvdl  *
     46   1.1      fvdl  * This code is derived from software contributed to The NetBSD Foundation
     47   1.1      fvdl  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
     48   1.1      fvdl  * NASA Ames Research Center, and by Frank van der Linden.
     49   1.1      fvdl  *
     50   1.1      fvdl  * Redistribution and use in source and binary forms, with or without
     51   1.1      fvdl  * modification, are permitted provided that the following conditions
     52   1.1      fvdl  * are met:
     53   1.1      fvdl  * 1. Redistributions of source code must retain the above copyright
     54   1.1      fvdl  *    notice, this list of conditions and the following disclaimer.
     55   1.1      fvdl  * 2. Redistributions in binary form must reproduce the above copyright
     56   1.1      fvdl  *    notice, this list of conditions and the following disclaimer in the
     57   1.1      fvdl  *    documentation and/or other materials provided with the distribution.
     58   1.1      fvdl  *
     59   1.1      fvdl  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     60   1.1      fvdl  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     61   1.1      fvdl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     62   1.1      fvdl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     63   1.1      fvdl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     64   1.1      fvdl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     65   1.1      fvdl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     66   1.1      fvdl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     67   1.1      fvdl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     68   1.1      fvdl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     69   1.1      fvdl  * POSSIBILITY OF SUCH DAMAGE.
     70   1.1      fvdl  */
     71   1.1      fvdl 
     72   1.1      fvdl #include <sys/cdefs.h>
     73  1.37   msaitoh __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.37 2020/11/04 09:15:10 msaitoh Exp $");
     74   1.1      fvdl 
     75  1.24     pooka #ifdef _KERNEL_OPT
     76   1.1      fvdl #include "opt_mii.h"
     77  1.24     pooka #endif
     78   1.1      fvdl 
     79   1.1      fvdl #include <sys/param.h>
     80   1.1      fvdl #include <sys/systm.h>
     81   1.1      fvdl #include <sys/kernel.h>
     82   1.1      fvdl #include <sys/device.h>
     83   1.1      fvdl #include <sys/socket.h>
     84   1.1      fvdl #include <sys/errno.h>
     85   1.1      fvdl 
     86   1.1      fvdl #include <net/if.h>
     87   1.1      fvdl #include <net/if_media.h>
     88   1.1      fvdl 
     89   1.1      fvdl #include <dev/mii/mii.h>
     90   1.1      fvdl #include <dev/mii/miivar.h>
     91   1.1      fvdl #include <dev/mii/miidevs.h>
     92   1.1      fvdl #include <dev/mii/igphyreg.h>
     93  1.21   msaitoh #include <dev/mii/igphyvar.h>
     94  1.19   msaitoh #include <dev/pci/if_wmvar.h>
     95   1.1      fvdl 
     96   1.1      fvdl static void igphy_reset(struct mii_softc *);
     97   1.1      fvdl static void igphy_load_dspcode(struct mii_softc *);
     98  1.20   msaitoh static void igphy_load_dspcode_igp3(struct mii_softc *);
     99   1.1      fvdl static void igphy_smartspeed_workaround(struct mii_softc *sc);
    100   1.1      fvdl 
    101  1.16   xtraeme static int	igphymatch(device_t, cfdata_t, void *);
    102  1.16   xtraeme static void	igphyattach(device_t, device_t, void *);
    103   1.1      fvdl 
    104  1.16   xtraeme CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc),
    105   1.1      fvdl     igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
    106   1.1      fvdl 
    107   1.4   thorpej static int	igphy_service(struct mii_softc *, struct mii_data *, int);
    108   1.4   thorpej static void	igphy_status(struct mii_softc *);
    109   1.1      fvdl 
    110   1.4   thorpej static const struct mii_phy_funcs igphy_funcs = {
    111   1.1      fvdl 	igphy_service, igphy_status, igphy_reset,
    112   1.1      fvdl };
    113   1.1      fvdl 
    114   1.4   thorpej static const struct mii_phydesc igphys[] = {
    115  1.30  christos 	MII_PHY_DESC(yyINTEL, IGP01E1000),
    116  1.30  christos 	MII_PHY_DESC(yyINTEL, I82566),
    117  1.30  christos 	MII_PHY_END,
    118   1.1      fvdl };
    119   1.1      fvdl 
    120   1.4   thorpej static int
    121  1.16   xtraeme igphymatch(device_t parent, cfdata_t match, void *aux)
    122   1.1      fvdl {
    123   1.1      fvdl 	struct mii_attach_args *ma = aux;
    124   1.1      fvdl 
    125   1.1      fvdl 	if (mii_phy_match(ma, igphys) != NULL)
    126   1.1      fvdl 		return 10;
    127   1.1      fvdl 
    128   1.1      fvdl 	return 0;
    129   1.1      fvdl }
    130   1.1      fvdl 
    131   1.4   thorpej static void
    132  1.16   xtraeme igphyattach(device_t parent, device_t self, void *aux)
    133   1.1      fvdl {
    134   1.7   thorpej 	struct mii_softc *sc = device_private(self);
    135   1.1      fvdl 	struct mii_attach_args *ma = aux;
    136   1.1      fvdl 	struct mii_data *mii = ma->mii_data;
    137   1.1      fvdl 	const struct mii_phydesc *mpd;
    138  1.31   msaitoh 	struct igphy_softc *igsc = (struct igphy_softc *)sc;
    139  1.19   msaitoh 	prop_dictionary_t dict;
    140   1.1      fvdl 
    141   1.1      fvdl 	mpd = mii_phy_match(ma, igphys);
    142   1.1      fvdl 	aprint_naive(": Media interface\n");
    143   1.1      fvdl 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
    144   1.1      fvdl 
    145  1.19   msaitoh 	dict = device_properties(parent);
    146  1.19   msaitoh 	if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
    147  1.19   msaitoh 		aprint_error("WARNING! Failed to get mactype\n");
    148  1.20   msaitoh 	if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
    149  1.20   msaitoh 		aprint_error("WARNING! Failed to get macflags\n");
    150  1.19   msaitoh 
    151  1.16   xtraeme 	sc->mii_dev = self;
    152   1.1      fvdl 	sc->mii_inst = mii->mii_instance;
    153   1.1      fvdl 	sc->mii_phy = ma->mii_phyno;
    154  1.25   msaitoh 	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
    155  1.25   msaitoh 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
    156  1.25   msaitoh 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
    157   1.1      fvdl 	sc->mii_funcs = &igphy_funcs;
    158   1.1      fvdl 	sc->mii_pdata = mii;
    159   1.1      fvdl 	sc->mii_flags = ma->mii_flags;
    160   1.1      fvdl 
    161  1.33   thorpej 	mii_lock(mii);
    162  1.33   thorpej 
    163   1.1      fvdl 	PHY_RESET(sc);
    164   1.1      fvdl 
    165  1.29   msaitoh 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
    166  1.29   msaitoh 	sc->mii_capabilities &= ma->mii_capmask;
    167   1.1      fvdl 	if (sc->mii_capabilities & BMSR_EXTSTAT)
    168  1.29   msaitoh 		PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
    169  1.32   msaitoh 
    170  1.33   thorpej 	mii_unlock(mii);
    171  1.33   thorpej 
    172  1.32   msaitoh 	mii_phy_add_media(sc);
    173   1.1      fvdl }
    174   1.1      fvdl 
    175  1.20   msaitoh typedef struct {
    176  1.20   msaitoh 	int reg;
    177  1.20   msaitoh 	uint16_t val;
    178  1.20   msaitoh } dspcode;
    179  1.20   msaitoh 
    180  1.20   msaitoh static const dspcode igp1code[] = {
    181  1.20   msaitoh 	{ 0x1f95, 0x0001 },
    182  1.20   msaitoh 	{ 0x1f71, 0xbd21 },
    183  1.20   msaitoh 	{ 0x1f79, 0x0018 },
    184  1.20   msaitoh 	{ 0x1f30, 0x1600 },
    185  1.20   msaitoh 	{ 0x1f31, 0x0014 },
    186  1.20   msaitoh 	{ 0x1f32, 0x161c },
    187  1.20   msaitoh 	{ 0x1f94, 0x0003 },
    188  1.20   msaitoh 	{ 0x1f96, 0x003f },
    189  1.20   msaitoh 	{ 0x2010, 0x0008 },
    190  1.20   msaitoh 	{ 0, 0 },
    191  1.20   msaitoh };
    192  1.20   msaitoh 
    193  1.20   msaitoh static const dspcode igp1code_r2[] = {
    194  1.20   msaitoh 	{ 0x1f73, 0x0099 },
    195  1.20   msaitoh 	{ 0, 0 },
    196  1.20   msaitoh };
    197  1.20   msaitoh 
    198  1.20   msaitoh static const dspcode igp3code[] = {
    199  1.20   msaitoh 	{ 0x2f5b, 0x9018},
    200  1.20   msaitoh 	{ 0x2f52, 0x0000},
    201  1.20   msaitoh 	{ 0x2fb1, 0x8b24},
    202  1.20   msaitoh 	{ 0x2fb2, 0xf8f0},
    203  1.20   msaitoh 	{ 0x2010, 0x10b0},
    204  1.20   msaitoh 	{ 0x2011, 0x0000},
    205  1.20   msaitoh 	{ 0x20dd, 0x249a},
    206  1.20   msaitoh 	{ 0x20de, 0x00d3},
    207  1.20   msaitoh 	{ 0x28b4, 0x04ce},
    208  1.20   msaitoh 	{ 0x2f70, 0x29e4},
    209  1.20   msaitoh 	{ 0x0000, 0x0140},
    210  1.20   msaitoh 	{ 0x1f30, 0x1606},
    211  1.20   msaitoh 	{ 0x1f31, 0xb814},
    212  1.20   msaitoh 	{ 0x1f35, 0x002a},
    213  1.20   msaitoh 	{ 0x1f3e, 0x0067},
    214  1.20   msaitoh 	{ 0x1f54, 0x0065},
    215  1.20   msaitoh 	{ 0x1f55, 0x002a},
    216  1.20   msaitoh 	{ 0x1f56, 0x002a},
    217  1.20   msaitoh 	{ 0x1f72, 0x3fb0},
    218  1.20   msaitoh 	{ 0x1f76, 0xc0ff},
    219  1.20   msaitoh 	{ 0x1f77, 0x1dec},
    220  1.20   msaitoh 	{ 0x1f78, 0xf9ef},
    221  1.20   msaitoh 	{ 0x1f79, 0x0210},
    222  1.20   msaitoh 	{ 0x1895, 0x0003},
    223  1.20   msaitoh 	{ 0x1796, 0x0008},
    224  1.20   msaitoh 	{ 0x1798, 0xd008},
    225  1.20   msaitoh 	{ 0x1898, 0xd918},
    226  1.20   msaitoh 	{ 0x187a, 0x0800},
    227  1.20   msaitoh 	{ 0x0019, 0x008d},
    228  1.20   msaitoh 	{ 0x001b, 0x2080},
    229  1.20   msaitoh 	{ 0x0014, 0x0045},
    230  1.20   msaitoh 	{ 0x0000, 0x1340},
    231  1.20   msaitoh 	{ 0, 0 },
    232  1.20   msaitoh };
    233  1.20   msaitoh 
    234  1.20   msaitoh /* DSP patch for igp1 and igp2 */
    235   1.1      fvdl static void
    236   1.1      fvdl igphy_load_dspcode(struct mii_softc *sc)
    237   1.1      fvdl {
    238  1.31   msaitoh 	struct igphy_softc *igsc = (struct igphy_softc *)sc;
    239  1.20   msaitoh 	const dspcode *code;
    240  1.20   msaitoh 	uint16_t reg;
    241   1.1      fvdl 	int i;
    242   1.1      fvdl 
    243  1.19   msaitoh 	/* This workaround is only for 82541 and 82547 */
    244  1.19   msaitoh 	switch (igsc->sc_mactype) {
    245  1.19   msaitoh 	case WM_T_82541:
    246  1.19   msaitoh 	case WM_T_82547:
    247  1.20   msaitoh 		code = igp1code;
    248  1.20   msaitoh 		break;
    249  1.19   msaitoh 	case WM_T_82541_2:
    250  1.19   msaitoh 	case WM_T_82547_2:
    251  1.20   msaitoh 		code = igp1code_r2;
    252  1.19   msaitoh 		break;
    253  1.19   msaitoh 	default:
    254  1.20   msaitoh 		return;	/* byebye */
    255  1.19   msaitoh 	}
    256  1.19   msaitoh 
    257  1.20   msaitoh 	/* Delay after phy reset to enable NVM configuration to load */
    258  1.20   msaitoh 	delay(20000);
    259  1.20   msaitoh 
    260  1.20   msaitoh 	/*
    261  1.20   msaitoh 	 * Save off the current value of register 0x2F5B to be restored at
    262  1.20   msaitoh 	 * the end of this routine.
    263  1.20   msaitoh 	 */
    264  1.29   msaitoh 	IGPHY_READ(sc, 0x2f5b, &reg);
    265  1.20   msaitoh 
    266  1.20   msaitoh 	/* Disabled the PHY transmitter */
    267  1.20   msaitoh 	IGPHY_WRITE(sc, 0x2f5b, 0x0003);
    268  1.20   msaitoh 
    269  1.20   msaitoh 	delay(20000);
    270   1.1      fvdl 
    271  1.35   msaitoh 	PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
    272   1.1      fvdl 	PHY_WRITE(sc, 0x0000, 0x0140);
    273   1.1      fvdl 
    274  1.20   msaitoh 	delay(5000);
    275   1.1      fvdl 
    276  1.20   msaitoh 	for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
    277  1.20   msaitoh 		IGPHY_WRITE(sc, code[i].reg, code[i].val);
    278   1.1      fvdl 
    279  1.35   msaitoh 	PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
    280   1.1      fvdl 	PHY_WRITE(sc, 0x0000, 0x3300);
    281  1.20   msaitoh 
    282  1.20   msaitoh 	delay(20000);
    283  1.20   msaitoh 
    284  1.20   msaitoh 	/* Now enable the transmitter */
    285  1.20   msaitoh 	IGPHY_WRITE(sc, 0x2f5b, reg);
    286  1.20   msaitoh }
    287  1.20   msaitoh 
    288  1.20   msaitoh static void
    289  1.20   msaitoh igphy_load_dspcode_igp3(struct mii_softc *sc)
    290  1.20   msaitoh {
    291  1.20   msaitoh 	const dspcode *code = igp3code;
    292  1.20   msaitoh 	int i;
    293  1.20   msaitoh 
    294  1.20   msaitoh 	for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
    295  1.20   msaitoh 		IGPHY_WRITE(sc, code[i].reg, code[i].val);
    296   1.1      fvdl }
    297   1.1      fvdl 
    298   1.1      fvdl static void
    299   1.1      fvdl igphy_reset(struct mii_softc *sc)
    300   1.1      fvdl {
    301  1.31   msaitoh 	struct igphy_softc *igsc = (struct igphy_softc *)sc;
    302   1.1      fvdl 	uint16_t fused, fine, coarse;
    303   1.1      fvdl 
    304  1.33   thorpej 	KASSERT(mii_locked(sc->mii_pdata));
    305  1.33   thorpej 
    306   1.1      fvdl 	mii_phy_reset(sc);
    307  1.20   msaitoh 	delay(150);
    308  1.20   msaitoh 
    309  1.20   msaitoh 	switch (igsc->sc_mactype) {
    310  1.20   msaitoh 	case WM_T_82541:
    311  1.20   msaitoh 	case WM_T_82547:
    312  1.20   msaitoh 	case WM_T_82541_2:
    313  1.20   msaitoh 	case WM_T_82547_2:
    314  1.20   msaitoh 		igphy_load_dspcode(sc);
    315  1.20   msaitoh 		break;
    316  1.20   msaitoh 	case WM_T_ICH8:
    317  1.20   msaitoh 	case WM_T_ICH9:
    318  1.20   msaitoh 		if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
    319  1.20   msaitoh 			igphy_load_dspcode_igp3(sc);
    320  1.20   msaitoh 		break;
    321  1.20   msaitoh 	default:	/* Not for ICH10, PCH and 8257[12] */
    322  1.20   msaitoh 		break;
    323  1.20   msaitoh 	}
    324   1.1      fvdl 
    325  1.19   msaitoh 	if (igsc->sc_mactype == WM_T_82547) {
    326  1.35   msaitoh 		IGPHY_READ(sc, IGPHY_ANALOG_SPARE_FUSE_STATUS, &fused);
    327  1.19   msaitoh 		if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
    328  1.35   msaitoh 			IGPHY_READ(sc, IGPHY_ANALOG_FUSE_STATUS, &fused);
    329  1.19   msaitoh 
    330  1.19   msaitoh 			fine = fused & ANALOG_FUSE_FINE_MASK;
    331  1.19   msaitoh 			coarse = fused & ANALOG_FUSE_COARSE_MASK;
    332  1.19   msaitoh 
    333  1.19   msaitoh 			if (coarse > ANALOG_FUSE_COARSE_THRESH) {
    334  1.19   msaitoh 				coarse -= ANALOG_FUSE_COARSE_10;
    335  1.19   msaitoh 				fine -= ANALOG_FUSE_FINE_1;
    336  1.19   msaitoh 			} else if (coarse == ANALOG_FUSE_COARSE_THRESH)
    337  1.19   msaitoh 				fine -= ANALOG_FUSE_FINE_10;
    338  1.19   msaitoh 
    339  1.19   msaitoh 			fused = (fused & ANALOG_FUSE_POLY_MASK) |
    340  1.19   msaitoh 			    (fine & ANALOG_FUSE_FINE_MASK) |
    341  1.19   msaitoh 			    (coarse & ANALOG_FUSE_COARSE_MASK);
    342  1.19   msaitoh 
    343  1.35   msaitoh 			IGPHY_WRITE(sc, IGPHY_ANALOG_FUSE_CONTROL, fused);
    344  1.35   msaitoh 			IGPHY_WRITE(sc, IGPHY_ANALOG_FUSE_BYPASS,
    345  1.19   msaitoh 			    ANALOG_FUSE_ENABLE_SW_CONTROL);
    346  1.19   msaitoh 		}
    347   1.1      fvdl 	}
    348  1.35   msaitoh 	PHY_WRITE(sc, IGPHY_PAGE_SELECT, 0x0000);
    349   1.1      fvdl }
    350   1.1      fvdl 
    351   1.1      fvdl 
    352   1.4   thorpej static int
    353   1.1      fvdl igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
    354   1.1      fvdl {
    355   1.1      fvdl 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    356   1.1      fvdl 	uint16_t reg;
    357   1.1      fvdl 
    358  1.33   thorpej 	KASSERT(mii_locked(mii));
    359  1.33   thorpej 
    360   1.1      fvdl 	switch (cmd) {
    361   1.1      fvdl 	case MII_POLLSTAT:
    362  1.31   msaitoh 		/* If we're not polling our PHY instance, just return. */
    363   1.1      fvdl 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    364  1.31   msaitoh 			return 0;
    365   1.1      fvdl 		break;
    366   1.1      fvdl 
    367   1.1      fvdl 	case MII_MEDIACHG:
    368   1.1      fvdl 		/*
    369   1.1      fvdl 		 * If the media indicates a different PHY instance,
    370   1.1      fvdl 		 * isolate ourselves.
    371   1.1      fvdl 		 */
    372   1.1      fvdl 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
    373  1.29   msaitoh 			PHY_READ(sc, MII_BMCR, &reg);
    374   1.1      fvdl 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
    375  1.31   msaitoh 			return 0;
    376   1.1      fvdl 		}
    377   1.1      fvdl 
    378  1.31   msaitoh 		/* If the interface is not up, don't do anything. */
    379   1.1      fvdl 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
    380   1.1      fvdl 			break;
    381   1.1      fvdl 
    382  1.35   msaitoh 		PHY_READ(sc, IGPHY_PORT_CTRL, &reg);
    383  1.11   msaitoh 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
    384  1.11   msaitoh 			reg |= PSCR_AUTO_MDIX;
    385  1.11   msaitoh 			reg &= ~PSCR_FORCE_MDI_MDIX;
    386  1.35   msaitoh 			PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
    387  1.11   msaitoh 		} else {
    388  1.11   msaitoh 			reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
    389  1.35   msaitoh 			PHY_WRITE(sc, IGPHY_PORT_CTRL, reg);
    390  1.11   msaitoh 		}
    391  1.11   msaitoh 
    392   1.1      fvdl 		mii_phy_setmedia(sc);
    393   1.1      fvdl 		break;
    394   1.1      fvdl 
    395   1.1      fvdl 	case MII_TICK:
    396  1.31   msaitoh 		/* If we're not currently selected, just return. */
    397   1.1      fvdl 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    398  1.31   msaitoh 			return 0;
    399   1.1      fvdl 
    400   1.1      fvdl 		igphy_smartspeed_workaround(sc);
    401   1.1      fvdl 
    402   1.1      fvdl 		if (mii_phy_tick(sc) == EJUSTRETURN)
    403  1.31   msaitoh 			return 0;
    404   1.1      fvdl 		break;
    405   1.1      fvdl 
    406   1.1      fvdl 	case MII_DOWN:
    407   1.1      fvdl 		mii_phy_down(sc);
    408  1.31   msaitoh 		return 0;
    409   1.1      fvdl 	}
    410   1.1      fvdl 
    411   1.1      fvdl 	/* Update the media status. */
    412   1.1      fvdl 	mii_phy_status(sc);
    413   1.1      fvdl 
    414   1.1      fvdl 	/* Callback if something changed. */
    415   1.1      fvdl 	mii_phy_update(sc, cmd);
    416  1.31   msaitoh 	return 0;
    417   1.1      fvdl }
    418   1.1      fvdl 
    419   1.1      fvdl 
    420   1.4   thorpej static void
    421   1.1      fvdl igphy_status(struct mii_softc *sc)
    422   1.1      fvdl {
    423   1.1      fvdl 	struct mii_data *mii = sc->mii_pdata;
    424   1.1      fvdl 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    425   1.1      fvdl 	uint16_t bmcr, pssr, gtsr, bmsr;
    426   1.1      fvdl 
    427  1.33   thorpej 	KASSERT(mii_locked(mii));
    428  1.33   thorpej 
    429   1.1      fvdl 	mii->mii_media_status = IFM_AVALID;
    430   1.1      fvdl 	mii->mii_media_active = IFM_ETHER;
    431   1.1      fvdl 
    432  1.35   msaitoh 	PHY_READ(sc, IGPHY_PORT_STATUS, &pssr);
    433   1.1      fvdl 
    434  1.36   msaitoh 	if (pssr & IGPHY_PSSR_LINK_UP)
    435   1.1      fvdl 		mii->mii_media_status |= IFM_ACTIVE;
    436   1.1      fvdl 
    437  1.29   msaitoh 	PHY_READ(sc, MII_BMCR, &bmcr);
    438   1.1      fvdl 	if (bmcr & BMCR_ISO) {
    439   1.1      fvdl 		mii->mii_media_active |= IFM_NONE;
    440   1.1      fvdl 		return;
    441   1.1      fvdl 	}
    442   1.1      fvdl 
    443   1.1      fvdl 	if (bmcr & BMCR_LOOP)
    444   1.1      fvdl 		mii->mii_media_active |= IFM_LOOP;
    445   1.1      fvdl 
    446  1.29   msaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
    447  1.29   msaitoh 	PHY_READ(sc, MII_BMSR, &bmsr);
    448   1.1      fvdl 
    449  1.31   msaitoh 	/* XXX can't check if the info is valid, no 'negotiation done' bit? */
    450   1.1      fvdl 	if (bmcr & BMCR_AUTOEN) {
    451   1.1      fvdl 		if ((bmsr & BMSR_ACOMP) == 0) {
    452   1.1      fvdl 			mii->mii_media_active |= IFM_NONE;
    453   1.1      fvdl 			return;
    454   1.1      fvdl 		}
    455  1.36   msaitoh 		switch (pssr & IGPHY_PSSR_SPEED_MASK) {
    456  1.36   msaitoh 		case IGPHY_PSSR_SPEED_1000MBPS:
    457   1.1      fvdl 			mii->mii_media_active |= IFM_1000_T;
    458  1.29   msaitoh 			PHY_READ(sc, MII_100T2SR, &gtsr);
    459   1.1      fvdl 			if (gtsr & GTSR_MS_RES)
    460   1.1      fvdl 				mii->mii_media_active |= IFM_ETH_MASTER;
    461   1.1      fvdl 			break;
    462   1.1      fvdl 
    463  1.36   msaitoh 		case IGPHY_PSSR_SPEED_100MBPS:
    464   1.1      fvdl 			mii->mii_media_active |= IFM_100_TX;
    465   1.1      fvdl 			break;
    466   1.1      fvdl 
    467  1.36   msaitoh 		case IGPHY_PSSR_SPEED_10MBPS:
    468   1.1      fvdl 			mii->mii_media_active |= IFM_10_T;
    469   1.1      fvdl 			break;
    470   1.1      fvdl 
    471   1.1      fvdl 		default:
    472   1.1      fvdl 			mii->mii_media_active |= IFM_NONE;
    473   1.1      fvdl 			mii->mii_media_status = 0;
    474   1.1      fvdl 			return;
    475   1.1      fvdl 		}
    476   1.1      fvdl 
    477  1.36   msaitoh 		if (pssr & IGPHY_PSSR_FULL_DUPLEX)
    478   1.2   thorpej 			mii->mii_media_active |=
    479   1.3   thorpej 			    IFM_FDX | mii_phy_flowstatus(sc);
    480  1.23   msaitoh 		else
    481  1.23   msaitoh 			mii->mii_media_active |= IFM_HDX;
    482   1.1      fvdl 	} else
    483   1.1      fvdl 		mii->mii_media_active = ife->ifm_media;
    484   1.1      fvdl }
    485   1.1      fvdl 
    486   1.1      fvdl static void
    487   1.1      fvdl igphy_smartspeed_workaround(struct mii_softc *sc)
    488   1.1      fvdl {
    489  1.31   msaitoh 	struct igphy_softc *igsc = (struct igphy_softc *)sc;
    490   1.5   thorpej 	uint16_t reg, gtsr, gtcr;
    491   1.5   thorpej 
    492  1.19   msaitoh 	/* This workaround is only for 82541 and 82547 */
    493  1.19   msaitoh 	switch (igsc->sc_mactype) {
    494  1.19   msaitoh 	case WM_T_82541:
    495  1.19   msaitoh 	case WM_T_82541_2:
    496  1.19   msaitoh 	case WM_T_82547:
    497  1.19   msaitoh 	case WM_T_82547_2:
    498  1.19   msaitoh 		break;
    499  1.19   msaitoh 	default:
    500  1.28   msaitoh 		/* byebye */
    501  1.19   msaitoh 		return;
    502  1.19   msaitoh 	}
    503  1.19   msaitoh 
    504  1.29   msaitoh 	PHY_READ(sc, MII_BMCR, &reg);
    505  1.29   msaitoh 	if ((reg & BMCR_AUTOEN) == 0)
    506   1.5   thorpej 		return;
    507   1.5   thorpej 
    508   1.5   thorpej 	/* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
    509   1.1      fvdl 
    510  1.29   msaitoh 	PHY_READ(sc, MII_BMSR, &reg);
    511  1.29   msaitoh 	PHY_READ(sc, MII_BMSR, &reg);
    512   1.5   thorpej 	if ((reg & BMSR_LINK) == 0) {
    513   1.5   thorpej 		switch (igsc->sc_smartspeed) {
    514   1.1      fvdl 		case 0:
    515  1.29   msaitoh 			PHY_READ(sc, MII_100T2SR, &gtsr);
    516   1.1      fvdl 			if (!(gtsr & GTSR_MAN_MS_FLT))
    517   1.1      fvdl 				break;
    518  1.29   msaitoh 			PHY_READ(sc, MII_100T2SR, &gtsr);
    519   1.1      fvdl 			if (gtsr & GTSR_MAN_MS_FLT) {
    520  1.29   msaitoh 				PHY_READ(sc, MII_100T2CR, &gtcr);
    521   1.1      fvdl 				if (gtcr & GTCR_MAN_MS) {
    522   1.1      fvdl 					gtcr &= ~GTCR_MAN_MS;
    523  1.29   msaitoh 					PHY_WRITE(sc, MII_100T2CR, gtcr);
    524   1.1      fvdl 				}
    525  1.34   msaitoh 				mii_phy_auto(sc);
    526   1.1      fvdl 			}
    527   1.1      fvdl 			break;
    528   1.1      fvdl 		case IGPHY_TICK_DOWNSHIFT:
    529  1.29   msaitoh 			PHY_READ(sc, MII_100T2CR, &gtcr);
    530   1.1      fvdl 			gtcr |= GTCR_MAN_MS;
    531   1.1      fvdl 			PHY_WRITE(sc, MII_100T2CR, gtcr);
    532  1.34   msaitoh 			mii_phy_auto(sc);
    533   1.1      fvdl 			break;
    534   1.1      fvdl 		default:
    535   1.1      fvdl 			break;
    536   1.1      fvdl 		}
    537   1.5   thorpej 		if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
    538   1.5   thorpej 			igsc->sc_smartspeed = 0;
    539   1.5   thorpej 	} else
    540   1.5   thorpej 		igsc->sc_smartspeed = 0;
    541   1.1      fvdl }
    542