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