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