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