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