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