Home | History | Annotate | Line # | Download | only in mii
igphy.c revision 1.4
      1 /*	$NetBSD: igphy.c,v 1.4 2004/08/23 06:16:06 thorpej 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  * 3. All advertising materials mentioning features or use of this software
     59  *    must display the following acknowledgement:
     60  *	This product includes software developed by the NetBSD
     61  *	Foundation, Inc. and its contributors.
     62  * 4. Neither the name of The NetBSD Foundation nor the names of its
     63  *    contributors may be used to endorse or promote products derived
     64  *    from this software without specific prior written permission.
     65  *
     66  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     67  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     68  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     69  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     70  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     71  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     72  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     73  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     74  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     75  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     76  * POSSIBILITY OF SUCH DAMAGE.
     77  */
     78 
     79 #include <sys/cdefs.h>
     80 __KERNEL_RCSID(0, "$NetBSD: igphy.c,v 1.4 2004/08/23 06:16:06 thorpej Exp $");
     81 
     82 #include "opt_mii.h"
     83 
     84 #include <sys/param.h>
     85 #include <sys/systm.h>
     86 #include <sys/kernel.h>
     87 #include <sys/device.h>
     88 #include <sys/socket.h>
     89 #include <sys/errno.h>
     90 
     91 #include <net/if.h>
     92 #include <net/if_media.h>
     93 
     94 #include <dev/mii/mii.h>
     95 #include <dev/mii/miivar.h>
     96 #include <dev/mii/miidevs.h>
     97 
     98 #include <dev/mii/igphyreg.h>
     99 
    100 static void igphy_reset(struct mii_softc *);
    101 static void igphy_load_dspcode(struct mii_softc *);
    102 #if 0
    103 static void igphy_smartspeed_workaround(struct mii_softc *sc);
    104 #endif
    105 
    106 static int	igphymatch(struct device *, struct cfdata *, void *);
    107 static void	igphyattach(struct device *, struct device *, void *);
    108 
    109 CFATTACH_DECL(igphy, sizeof(struct mii_softc),
    110     igphymatch, igphyattach, mii_phy_detach, mii_phy_activate);
    111 
    112 static int	igphy_service(struct mii_softc *, struct mii_data *, int);
    113 static void	igphy_status(struct mii_softc *);
    114 
    115 static const struct mii_phy_funcs igphy_funcs = {
    116 	igphy_service, igphy_status, igphy_reset,
    117 };
    118 
    119 static const struct mii_phydesc igphys[] = {
    120 	{ MII_OUI_yyINTEL,		MII_MODEL_yyINTEL_IGP01E1000,
    121 	  MII_STR_yyINTEL_IGP01E1000 },
    122 
    123 	{0,				0,
    124 	 NULL },
    125 };
    126 
    127 static int
    128 igphymatch(struct device *parent, struct cfdata *match, void *aux)
    129 {
    130 	struct mii_attach_args *ma = aux;
    131 
    132 	if (mii_phy_match(ma, igphys) != NULL)
    133 		return 10;
    134 
    135 	return 0;
    136 }
    137 
    138 static void
    139 igphyattach(struct device *parent, struct device *self, void *aux)
    140 {
    141 	struct mii_softc *sc = (struct mii_softc *)self;
    142 	struct mii_attach_args *ma = aux;
    143 	struct mii_data *mii = ma->mii_data;
    144 	const struct mii_phydesc *mpd;
    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 	sc->mii_inst = mii->mii_instance;
    151 	sc->mii_phy = ma->mii_phyno;
    152 	sc->mii_funcs = &igphy_funcs;
    153 	sc->mii_pdata = mii;
    154 	sc->mii_flags = ma->mii_flags;
    155 	sc->mii_anegticks = 10;
    156 
    157 	PHY_RESET(sc);
    158 
    159 	sc->mii_capabilities =
    160 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
    161 	if (sc->mii_capabilities & BMSR_EXTSTAT)
    162 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
    163 	aprint_normal("%s: ", sc->mii_dev.dv_xname);
    164 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
    165 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
    166 		aprint_error("no media present");
    167 	else
    168 		mii_phy_add_media(sc);
    169 	aprint_normal("\n");
    170 }
    171 
    172 static void
    173 igphy_load_dspcode(struct mii_softc *sc)
    174 {
    175 	static const struct {
    176 		int reg;
    177 		uint16_t val;
    178 	} dspcode[] = {
    179 		{ 0x1f95, 0x0001 },
    180 		{ 0x1f71, 0xbd21 },
    181 		{ 0x1f79, 0x0018 },
    182 		{ 0x1f30, 0x1600 },
    183 		{ 0x1f31, 0x0014 },
    184 		{ 0x1f32, 0x161c },
    185 		{ 0x1f94, 0x0003 },
    186 		{ 0x1f96, 0x003f },
    187 		{ 0x2010, 0x0008 },
    188 		{ 0, 0 },
    189 	};
    190 	int i;
    191 
    192 	delay(10);
    193 
    194 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT, 0x0000);
    195 	PHY_WRITE(sc, 0x0000, 0x0140);
    196 
    197 	delay(5);
    198 
    199 	for (i = 0; dspcode[i].reg != 0; i++)
    200 		IGPHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
    201 
    202 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
    203 	PHY_WRITE(sc, 0x0000, 0x3300);
    204 }
    205 
    206 static void
    207 igphy_reset(struct mii_softc *sc)
    208 {
    209 	uint16_t fused, fine, coarse;
    210 
    211 	mii_phy_reset(sc);
    212 	igphy_load_dspcode(sc);
    213 
    214 	fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_SPARE_FUSE_STATUS);
    215 	if ((fused & ANALOG_SPARE_FUSE_ENABLED) == 0) {
    216 		fused = IGPHY_READ(sc, MII_IGPHY_ANALOG_FUSE_STATUS);
    217 
    218 		fine = fused & ANALOG_FUSE_FINE_MASK;
    219 		coarse = fused & ANALOG_FUSE_COARSE_MASK;
    220 
    221 		if (coarse > ANALOG_FUSE_COARSE_THRESH) {
    222 			coarse -= ANALOG_FUSE_COARSE_10;
    223 			fine -= ANALOG_FUSE_FINE_1;
    224 		} else if (coarse == ANALOG_FUSE_COARSE_THRESH)
    225 			fine -= ANALOG_FUSE_FINE_10;
    226 
    227 		fused = (fused & ANALOG_FUSE_POLY_MASK) |
    228 			(fine & ANALOG_FUSE_FINE_MASK) |
    229 			(coarse & ANALOG_FUSE_COARSE_MASK);
    230 
    231 		IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_CONTROL, fused);
    232 		IGPHY_WRITE(sc, MII_IGPHY_ANALOG_FUSE_BYPASS,
    233 		    ANALOG_FUSE_ENABLE_SW_CONTROL);
    234 	}
    235 	PHY_WRITE(sc, MII_IGPHY_PAGE_SELECT,0x0000);
    236 }
    237 
    238 
    239 static int
    240 igphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
    241 {
    242 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    243 	uint16_t reg;
    244 
    245 	switch (cmd) {
    246 	case MII_POLLSTAT:
    247 		/*
    248 		 * If we're not polling our PHY instance, just return.
    249 		 */
    250 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    251 			return (0);
    252 		break;
    253 
    254 	case MII_MEDIACHG:
    255 		/*
    256 		 * If the media indicates a different PHY instance,
    257 		 * isolate ourselves.
    258 		 */
    259 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
    260 			reg = PHY_READ(sc, MII_BMCR);
    261 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
    262 			return (0);
    263 		}
    264 
    265 		/*
    266 		 * If the interface is not up, don't do anything.
    267 		 */
    268 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
    269 			break;
    270 
    271 		mii_phy_setmedia(sc);
    272 		break;
    273 
    274 	case MII_TICK:
    275 		/*
    276 		 * If we're not currently selected, just return.
    277 		 */
    278 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    279 			return (0);
    280 
    281 #if 0
    282 		igphy_smartspeed_workaround(sc);
    283 #endif
    284 
    285 		if (mii_phy_tick(sc) == EJUSTRETURN)
    286 			return (0);
    287 		break;
    288 
    289 	case MII_DOWN:
    290 		mii_phy_down(sc);
    291 		return (0);
    292 	}
    293 
    294 	/* Update the media status. */
    295 	mii_phy_status(sc);
    296 
    297 	/* Callback if something changed. */
    298 	mii_phy_update(sc, cmd);
    299 	return (0);
    300 }
    301 
    302 
    303 static void
    304 igphy_status(struct mii_softc *sc)
    305 {
    306 	struct mii_data *mii = sc->mii_pdata;
    307 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    308 	uint16_t bmcr, pssr, gtsr, bmsr;
    309 
    310 	mii->mii_media_status = IFM_AVALID;
    311 	mii->mii_media_active = IFM_ETHER;
    312 
    313 	pssr = PHY_READ(sc, MII_IGPHY_PORT_STATUS);
    314 
    315 	if (pssr & PSSR_LINK_UP)
    316 		mii->mii_media_status |= IFM_ACTIVE;
    317 
    318 	bmcr = PHY_READ(sc, MII_BMCR);
    319 	if (bmcr & BMCR_ISO) {
    320 		mii->mii_media_active |= IFM_NONE;
    321 		mii->mii_media_status = 0;
    322 		return;
    323 	}
    324 
    325 	if (bmcr & BMCR_LOOP)
    326 		mii->mii_media_active |= IFM_LOOP;
    327 
    328 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
    329 
    330 	/*
    331 	 * XXX can't check if the info is valid, no
    332 	 * 'negotiation done' bit?
    333 	 */
    334 	if (bmcr & BMCR_AUTOEN) {
    335 		if ((bmsr & BMSR_ACOMP) == 0) {
    336 			mii->mii_media_active |= IFM_NONE;
    337 			return;
    338 		}
    339 		switch (pssr & PSSR_SPEED_MASK) {
    340 		case PSSR_SPEED_1000MBPS:
    341 			mii->mii_media_active |= IFM_1000_T;
    342 			gtsr = PHY_READ(sc, MII_100T2SR);
    343 			if (gtsr & GTSR_MS_RES)
    344 				mii->mii_media_active |= IFM_ETH_MASTER;
    345 			break;
    346 
    347 		case PSSR_SPEED_100MBPS:
    348 			mii->mii_media_active |= IFM_100_TX;
    349 			break;
    350 
    351 		case PSSR_SPEED_10MBPS:
    352 			mii->mii_media_active |= IFM_10_T;
    353 			break;
    354 
    355 		default:
    356 			mii->mii_media_active |= IFM_NONE;
    357 			mii->mii_media_status = 0;
    358 			return;
    359 		}
    360 
    361 		if (pssr & PSSR_FULL_DUPLEX)
    362 			mii->mii_media_active |=
    363 			    IFM_FDX | mii_phy_flowstatus(sc);
    364 	} else
    365 		mii->mii_media_active = ife->ifm_media;
    366 }
    367 
    368 #if 0
    369 static void
    370 igphy_smartspeed_workaround(struct mii_softc *sc)
    371 {
    372 	uint16_t reg, gtsr, gctr;
    373 
    374 	reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
    375 	if (!(reg & BMSR_LINK)) {
    376 		switch (sc->mii_ticks) {
    377 		case 0:
    378 			gtsr = PHY_READ(sc, MII_100T2SR);
    379 			if (!(gtsr & GTSR_MAN_MS_FLT))
    380 				break;
    381 			gtsr = PHY_READ(sc, MII_100T2SR);
    382 			if (gtsr & GTSR_MAN_MS_FLT) {
    383 				gtcr = PHY_READ(sc, MII_100T2CR);
    384 				if (gtcr & GTCR_MAN_MS) {
    385 					gtcr &= ~GTCR_MAN_MS;
    386 					PHY_WRITE(sc, MII_100T2CR,
    387 					    gtcr);
    388 				}
    389 				mii_phy_auto(sc, 0);
    390 				sc->mii_ticks++;
    391 			}
    392 			break;
    393 		case IGPHY_TICK_DOWNSHIFT:
    394 			gtcr = PHY_READ(sc, MII_100T2CR);
    395 			gtcr |= GTCR_MAN_MS;
    396 			PHY_WRITE(sc, MII_100T2CR, gtcr);
    397 			mii_phy_auto(sc, 0);
    398 			break;
    399 		default:
    400 			break;
    401 		}
    402 	}
    403 }
    404 #endif
    405