Home | History | Annotate | Line # | Download | only in mii
igphy.c revision 1.21.16.2
      1 /*	$NetBSD: igphy.c,v 1.21.16.2 2016/05/06 18:43:34 snj Exp $	*/
      2 
      3 /*
      4  * The Intel copyright applies to the analog register setup, and the
      5  * (currently disabled) 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.21.16.2 2016/05/06 18:43:34 snj Exp $");
     74 
     75 #include "opt_mii.h"
     76 
     77 #include <sys/param.h>
     78 #include <sys/systm.h>
     79 #include <sys/kernel.h>
     80 #include <sys/device.h>
     81 #include <sys/socket.h>
     82 #include <sys/errno.h>
     83 
     84 #include <net/if.h>
     85 #include <net/if_media.h>
     86 
     87 #include <dev/mii/mii.h>
     88 #include <dev/mii/miivar.h>
     89 #include <dev/mii/miidevs.h>
     90 #include <dev/mii/igphyreg.h>
     91 #include <dev/mii/igphyvar.h>
     92 #include <dev/pci/if_wmvar.h>
     93 
     94 static void igphy_reset(struct mii_softc *);
     95 static void igphy_load_dspcode(struct mii_softc *);
     96 static void igphy_load_dspcode_igp3(struct mii_softc *);
     97 static void igphy_smartspeed_workaround(struct mii_softc *sc);
     98 
     99 static int	igphymatch(device_t, cfdata_t, void *);
    100 static void	igphyattach(device_t, device_t, void *);
    101 
    102 CFATTACH_DECL_NEW(igphy, sizeof(struct igphy_softc),
    103     igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
    104 
    105 static int	igphy_service(struct mii_softc *, struct mii_data *, int);
    106 static void	igphy_status(struct mii_softc *);
    107 
    108 static const struct mii_phy_funcs igphy_funcs = {
    109 	igphy_service, igphy_status, igphy_reset,
    110 };
    111 
    112 static const struct mii_phydesc igphys[] = {
    113 	{ MII_OUI_yyINTEL,		MII_MODEL_yyINTEL_IGP01E1000,
    114 	  MII_STR_yyINTEL_IGP01E1000 },
    115 
    116 	{ MII_OUI_yyINTEL,		MII_MODEL_yyINTEL_I82566,
    117 	  MII_STR_yyINTEL_I82566 },
    118 
    119 	{0,				0,
    120 	 NULL },
    121 };
    122 
    123 static int
    124 igphymatch(device_t parent, cfdata_t match, void *aux)
    125 {
    126 	struct mii_attach_args *ma = aux;
    127 
    128 	if (mii_phy_match(ma, igphys) != NULL)
    129 		return 10;
    130 
    131 	return 0;
    132 }
    133 
    134 static void
    135 igphyattach(device_t parent, device_t self, void *aux)
    136 {
    137 	struct mii_softc *sc = device_private(self);
    138 	struct mii_attach_args *ma = aux;
    139 	struct mii_data *mii = ma->mii_data;
    140 	const struct mii_phydesc *mpd;
    141 	struct igphy_softc *igsc = (struct igphy_softc *) sc;
    142 	prop_dictionary_t dict;
    143 
    144 	mpd = mii_phy_match(ma, igphys);
    145 	aprint_naive(": Media interface\n");
    146 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
    147 
    148 	dict = device_properties(parent);
    149 	if (!prop_dictionary_get_uint32(dict, "mactype", &igsc->sc_mactype))
    150 		aprint_error("WARNING! Failed to get mactype\n");
    151 	if (!prop_dictionary_get_uint32(dict, "macflags", &igsc->sc_macflags))
    152 		aprint_error("WARNING! Failed to get macflags\n");
    153 
    154 	sc->mii_dev = self;
    155 	sc->mii_inst = mii->mii_instance;
    156 	sc->mii_phy = ma->mii_phyno;
    157 	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
    158 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
    159 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
    160 	sc->mii_funcs = &igphy_funcs;
    161 	sc->mii_pdata = mii;
    162 	sc->mii_flags = ma->mii_flags;
    163 	sc->mii_anegticks = MII_ANEGTICKS_GIGE;
    164 
    165 	PHY_RESET(sc);
    166 
    167 	sc->mii_capabilities =
    168 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
    169 	if (sc->mii_capabilities & BMSR_EXTSTAT)
    170 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
    171 	aprint_normal_dev(self, "");
    172 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
    173 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
    174 		aprint_error("no media present");
    175 	else
    176 		mii_phy_add_media(sc);
    177 	aprint_normal("\n");
    178 }
    179 
    180 typedef struct {
    181 	int reg;
    182 	uint16_t val;
    183 } dspcode;
    184 
    185 static const dspcode igp1code[] = {
    186 	{ 0x1f95, 0x0001 },
    187 	{ 0x1f71, 0xbd21 },
    188 	{ 0x1f79, 0x0018 },
    189 	{ 0x1f30, 0x1600 },
    190 	{ 0x1f31, 0x0014 },
    191 	{ 0x1f32, 0x161c },
    192 	{ 0x1f94, 0x0003 },
    193 	{ 0x1f96, 0x003f },
    194 	{ 0x2010, 0x0008 },
    195 	{ 0, 0 },
    196 };
    197 
    198 static const dspcode igp1code_r2[] = {
    199 	{ 0x1f73, 0x0099 },
    200 	{ 0, 0 },
    201 };
    202 
    203 static const dspcode igp3code[] = {
    204 	{ 0x2f5b, 0x9018},
    205 	{ 0x2f52, 0x0000},
    206 	{ 0x2fb1, 0x8b24},
    207 	{ 0x2fb2, 0xf8f0},
    208 	{ 0x2010, 0x10b0},
    209 	{ 0x2011, 0x0000},
    210 	{ 0x20dd, 0x249a},
    211 	{ 0x20de, 0x00d3},
    212 	{ 0x28b4, 0x04ce},
    213 	{ 0x2f70, 0x29e4},
    214 	{ 0x0000, 0x0140},
    215 	{ 0x1f30, 0x1606},
    216 	{ 0x1f31, 0xb814},
    217 	{ 0x1f35, 0x002a},
    218 	{ 0x1f3e, 0x0067},
    219 	{ 0x1f54, 0x0065},
    220 	{ 0x1f55, 0x002a},
    221 	{ 0x1f56, 0x002a},
    222 	{ 0x1f72, 0x3fb0},
    223 	{ 0x1f76, 0xc0ff},
    224 	{ 0x1f77, 0x1dec},
    225 	{ 0x1f78, 0xf9ef},
    226 	{ 0x1f79, 0x0210},
    227 	{ 0x1895, 0x0003},
    228 	{ 0x1796, 0x0008},
    229 	{ 0x1798, 0xd008},
    230 	{ 0x1898, 0xd918},
    231 	{ 0x187a, 0x0800},
    232 	{ 0x0019, 0x008d},
    233 	{ 0x001b, 0x2080},
    234 	{ 0x0014, 0x0045},
    235 	{ 0x0000, 0x1340},
    236 	{ 0, 0 },
    237 };
    238 
    239 /* DSP patch for igp1 and igp2 */
    240 static void
    241 igphy_load_dspcode(struct mii_softc *sc)
    242 {
    243 	struct igphy_softc *igsc = (struct igphy_softc *) sc;
    244 	const dspcode *code;
    245 	uint16_t reg;
    246 	int i;
    247 
    248 	/* This workaround is only for 82541 and 82547 */
    249 	switch (igsc->sc_mactype) {
    250 	case WM_T_82541:
    251 	case WM_T_82547:
    252 		code = igp1code;
    253 		break;
    254 	case WM_T_82541_2:
    255 	case WM_T_82547_2:
    256 		code = igp1code_r2;
    257 		break;
    258 	default:
    259 		return;	/* byebye */
    260 	}
    261 
    262 	/* Delay after phy reset to enable NVM configuration to load */
    263 	delay(20000);
    264 
    265 	/*
    266 	 * Save off the current value of register 0x2F5B to be restored at
    267 	 * the end of this routine.
    268 	 */
    269 	reg = IGPHY_READ(sc, 0x2f5b);
    270 
    271 	/* Disabled the PHY transmitter */
    272 	IGPHY_WRITE(sc, 0x2f5b, 0x0003);
    273 
    274 	delay(20000);
    275 
    276 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
    277 	PHY_WRITE(sc, 0x0000, 0x0140);
    278 
    279 	delay(5000);
    280 
    281 	for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
    282 		IGPHY_WRITE(sc, code[i].reg, code[i].val);
    283 
    284 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
    285 	PHY_WRITE(sc, 0x0000, 0x3300);
    286 
    287 	delay(20000);
    288 
    289 	/* Now enable the transmitter */
    290 	IGPHY_WRITE(sc, 0x2f5b, reg);
    291 }
    292 
    293 static void
    294 igphy_load_dspcode_igp3(struct mii_softc *sc)
    295 {
    296 	const dspcode *code = igp3code;
    297 	int i;
    298 
    299 	for (i = 0; !((code[i].reg == 0) && (code[i].val == 0)); i++)
    300 		IGPHY_WRITE(sc, code[i].reg, code[i].val);
    301 }
    302 
    303 static void
    304 igphy_reset(struct mii_softc *sc)
    305 {
    306 	struct igphy_softc *igsc = (struct igphy_softc *) sc;
    307 	uint16_t fused, fine, coarse;
    308 
    309 	mii_phy_reset(sc);
    310 	delay(150);
    311 
    312 	switch (igsc->sc_mactype) {
    313 	case WM_T_82541:
    314 	case WM_T_82547:
    315 	case WM_T_82541_2:
    316 	case WM_T_82547_2:
    317 		igphy_load_dspcode(sc);
    318 		break;
    319 	case WM_T_ICH8:
    320 	case WM_T_ICH9:
    321 		if ((igsc->sc_macflags & WM_F_EEPROM_INVALID) != 0)
    322 			igphy_load_dspcode_igp3(sc);
    323 		break;
    324 	default:	/* Not for ICH10, PCH and 8257[12] */
    325 		break;
    326 	}
    327 
    328 	if (igsc->sc_mactype == WM_T_82547) {
    329 		fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
    330 		if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
    331 			fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
    332 
    333 			fine = fused & ANALOG_FUSE_FINE_MASK;
    334 			coarse = fused & ANALOG_FUSE_COARSE_MASK;
    335 
    336 			if (coarse > ANALOG_FUSE_COARSE_THRESH) {
    337 				coarse -= ANALOG_FUSE_COARSE_10;
    338 				fine -= ANALOG_FUSE_FINE_1;
    339 			} else if (coarse == ANALOG_FUSE_COARSE_THRESH)
    340 				fine -= ANALOG_FUSE_FINE_10;
    341 
    342 			fused = (fused & ANALOG_FUSE_POLY_MASK) |
    343 			    (fine & ANALOG_FUSE_FINE_MASK) |
    344 			    (coarse & ANALOG_FUSE_COARSE_MASK);
    345 
    346 			IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
    347 			IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
    348 			    ANALOG_FUSE_ENABLE_SW_CONTROL);
    349 		}
    350 	}
    351 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
    352 }
    353 
    354 
    355 static int
    356 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
    357 {
    358 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    359 	uint16_t reg;
    360 
    361 	switch (cmd) {
    362 	case MII_POLLSTAT:
    363 		/*
    364 		 * If we're not polling our PHY instance, just return.
    365 		 */
    366 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    367 			return (0);
    368 		break;
    369 
    370 	case MII_MEDIACHG:
    371 		/*
    372 		 * If the media indicates a different PHY instance,
    373 		 * isolate ourselves.
    374 		 */
    375 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
    376 			reg = PHY_READ(sc, MII_BMCR);
    377 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
    378 			return (0);
    379 		}
    380 
    381 		/*
    382 		 * If the interface is not up, don't do anything.
    383 		 */
    384 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
    385 			break;
    386 
    387 		reg = PHY_READ(sc, MII_IGPHY_PORT_CTRL);
    388 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
    389 			reg |= PSCR_AUTO_MDIX;
    390 			reg &= ~PSCR_FORCE_MDI_MDIX;
    391 			PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
    392 		} else {
    393 			reg &= ~(PSCR_AUTO_MDIX | PSCR_FORCE_MDI_MDIX);
    394 			PHY_WRITE(sc, MII_IGPHY_PORT_CTRL, reg);
    395 		}
    396 
    397 		mii_phy_setmedia(sc);
    398 		break;
    399 
    400 	case MII_TICK:
    401 		/*
    402 		 * If we're not currently selected, just return.
    403 		 */
    404 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    405 			return (0);
    406 
    407 		igphy_smartspeed_workaround(sc);
    408 
    409 		if (mii_phy_tick(sc) == EJUSTRETURN)
    410 			return (0);
    411 		break;
    412 
    413 	case MII_DOWN:
    414 		mii_phy_down(sc);
    415 		return (0);
    416 	}
    417 
    418 	/* Update the media status. */
    419 	mii_phy_status(sc);
    420 
    421 	/* Callback if something changed. */
    422 	mii_phy_update(sc, cmd);
    423 	return (0);
    424 }
    425 
    426 
    427 static void
    428 igphy_status(struct mii_softc *sc)
    429 {
    430 	struct mii_data *mii = sc->mii_pdata;
    431 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    432 	uint16_t bmcr, pssr, gtsr, bmsr;
    433 
    434 	mii->mii_media_status = IFM_AVALID;
    435 	mii->mii_media_active = IFM_ETHER;
    436 
    437 	pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
    438 
    439 	if (pssr & PSSR_LINK_UP)
    440 		mii->mii_media_status |= IFM_ACTIVE;
    441 
    442 	bmcr = PHY_READ(sc, MII_BMCR);
    443 	if (bmcr & BMCR_ISO) {
    444 		mii->mii_media_active |= IFM_NONE;
    445 		mii->mii_media_status = 0;
    446 		return;
    447 	}
    448 
    449 	if (bmcr & BMCR_LOOP)
    450 		mii->mii_media_active |= IFM_LOOP;
    451 
    452 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
    453 
    454 	/*
    455 	 * XXX can't check if the info is valid, no
    456 	 * 'negotiation done' bit?
    457 	 */
    458 	if (bmcr & BMCR_AUTOEN) {
    459 		if ((bmsr & BMSR_ACOMP) == 0) {
    460 			mii->mii_media_active |= IFM_NONE;
    461 			return;
    462 		}
    463 		switch (pssr & PSSR_SPEED_MASK) {
    464 		case PSSR_SPEED_1000MBPS:
    465 			mii->mii_media_active |= IFM_1000_T;
    466 			gtsr = PHY_READ(sc, MII_100T2SR);
    467 			if (gtsr & GTSR_MS_RES)
    468 				mii->mii_media_active |= IFM_ETH_MASTER;
    469 			break;
    470 
    471 		case PSSR_SPEED_100MBPS:
    472 			mii->mii_media_active |= IFM_100_TX;
    473 			break;
    474 
    475 		case PSSR_SPEED_10MBPS:
    476 			mii->mii_media_active |= IFM_10_T;
    477 			break;
    478 
    479 		default:
    480 			mii->mii_media_active |= IFM_NONE;
    481 			mii->mii_media_status = 0;
    482 			return;
    483 		}
    484 
    485 		if (pssr & PSSR_FULL_DUPLEX)
    486 			mii->mii_media_active |=
    487 			    IFM_FDX | mii_phy_flowstatus(sc);
    488 		else
    489 			mii->mii_media_active |= IFM_HDX;
    490 	} else
    491 		mii->mii_media_active = ife->ifm_media;
    492 }
    493 
    494 static void
    495 igphy_smartspeed_workaround(struct mii_softc *sc)
    496 {
    497 	struct igphy_softc *igsc = (struct igphy_softc *) sc;
    498 	uint16_t reg, gtsr, gtcr;
    499 
    500 
    501 	/* This workaround is only for 82541 and 82547 */
    502 	switch (igsc->sc_mactype) {
    503 	case WM_T_82541:
    504 	case WM_T_82541_2:
    505 	case WM_T_82547:
    506 	case WM_T_82547_2:
    507 		break;
    508 	default:
    509 		/* byebye */
    510 		return;
    511 	}
    512 
    513 	if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0)
    514 		return;
    515 
    516 	/* XXX Assume 1000TX-FDX is advertized if doing autonegotiation. */
    517 
    518 	reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
    519 	if ((reg & BMSR_LINK) == 0) {
    520 		switch (igsc->sc_smartspeed) {
    521 		case 0:
    522 			gtsr = PHY_READ(sc, MII_100T2SR);
    523 			if (!(gtsr & GTSR_MAN_MS_FLT))
    524 				break;
    525 			gtsr = PHY_READ(sc, MII_100T2SR);
    526 			if (gtsr & GTSR_MAN_MS_FLT) {
    527 				gtcr = PHY_READ(sc, MII_100T2CR);
    528 				if (gtcr & GTCR_MAN_MS) {
    529 					gtcr &= ~GTCR_MAN_MS;
    530 					PHY_WRITE(sc, MII_100T2CR,
    531 					    gtcr);
    532 				}
    533 				mii_phy_auto(sc, 0);
    534 			}
    535 			break;
    536 		case IGPHY_TICK_DOWNSHIFT:
    537 			gtcr = PHY_READ(sc, MII_100T2CR);
    538 			gtcr |= GTCR_MAN_MS;
    539 			PHY_WRITE(sc, MII_100T2CR, gtcr);
    540 			mii_phy_auto(sc, 0);
    541 			break;
    542 		default:
    543 			break;
    544 		}
    545 		if (igsc->sc_smartspeed++ == IGPHY_TICK_MAX)
    546 			igsc->sc_smartspeed = 0;
    547 	} else
    548 		igsc->sc_smartspeed = 0;
    549 }
    550