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