Home | History | Annotate | Line # | Download | only in mii
ikphy.c revision 1.3
      1 /*	$NetBSD: ikphy.c,v 1.3 2006/11/16 21:24:07 christos Exp $	*/
      2 
      3 /*******************************************************************************
      4 Copyright (c) 2001-2005, Intel Corporation
      5 All rights reserved.
      6 
      7 Redistribution and use in source and binary forms, with or without
      8 modification, are permitted provided that the following conditions are met:
      9 
     10  1. Redistributions of source code must retain the above copyright notice,
     11     this list of conditions and the following disclaimer.
     12 
     13  2. Redistributions in binary form must reproduce the above copyright
     14     notice, this list of conditions and the following disclaimer in the
     15     documentation and/or other materials provided with the distribution.
     16 
     17  3. Neither the name of the Intel Corporation nor the names of its
     18     contributors may be used to endorse or promote products derived from
     19     this software without specific prior written permission.
     20 
     21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31 POSSIBILITY OF SUCH DAMAGE.
     32 *******************************************************************************/
     33 /*
     34  * Copyright (c) 2006 Manuel Bouyer.  All rights reserved.
     35  *
     36  * Redistribution and use in source and binary forms, with or without
     37  * modification, are permitted provided that the following conditions
     38  * are met:
     39  * 1. Redistributions of source code must retain the above copyright
     40  *    notice, this list of conditions and the following disclaimer.
     41  * 2. Redistributions in binary form must reproduce the above copyright
     42  *    notice, this list of conditions and the following disclaimer in the
     43  *    documentation and/or other materials provided with the distribution.
     44  * 3. All advertising materials mentioning features or use of this software
     45  *    must display the following acknowledgement:
     46  *	This product includes software developed by Manuel Bouyer.
     47  * 4. The name of the author may not be used to endorse or promote products
     48  *    derived from this software without specific prior written permission.
     49  *
     50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     51  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     52  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     53  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     54  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     55  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     56  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     57  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     59  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     60  */
     61 
     62 /*
     63  * driver for Intel's i82563 ethernet 10/100/1000 PHY
     64  */
     65 
     66 #include <sys/cdefs.h>
     67 __KERNEL_RCSID(0, "$NetBSD: ikphy.c,v 1.3 2006/11/16 21:24:07 christos Exp $");
     68 
     69 #include <sys/param.h>
     70 #include <sys/systm.h>
     71 #include <sys/kernel.h>
     72 #include <sys/device.h>
     73 #include <sys/socket.h>
     74 #include <sys/errno.h>
     75 
     76 #include <net/if.h>
     77 #include <net/if_media.h>
     78 
     79 #include <dev/mii/mii.h>
     80 #include <dev/mii/miivar.h>
     81 #include <dev/mii/miidevs.h>
     82 
     83 #include <dev/mii/ikphyreg.h>
     84 
     85 static int	ikphymatch(struct device *, struct cfdata *, void *);
     86 static void	ikphyattach(struct device *, struct device *, void *);
     87 
     88 CFATTACH_DECL(ikphy, sizeof(struct mii_softc),
     89     ikphymatch, ikphyattach, mii_phy_detach, mii_phy_activate);
     90 
     91 static int	ikphy_service(struct mii_softc *, struct mii_data *, int);
     92 static void	ikphy_status(struct mii_softc *);
     93 static void	ikphy_setmedia(struct mii_softc *);
     94 
     95 static const struct mii_phy_funcs ikphy_funcs = {
     96 	ikphy_service, ikphy_status, mii_phy_reset,
     97 };
     98 
     99 static const struct mii_phydesc ikphys[] = {
    100 	{ MII_OUI_xxMARVELL,		MII_MODEL_xxMARVELL_I82563,
    101 	  MII_STR_xxMARVELL_I82563 },
    102 
    103 	{ 0,				0,
    104 	  NULL },
    105 };
    106 
    107 static int
    108 ikphymatch(struct device *parent, struct cfdata *match,
    109     void *aux)
    110 {
    111 	struct mii_attach_args *ma = aux;
    112 
    113 	if (mii_phy_match(ma, ikphys) != NULL)
    114 		return (10);
    115 
    116 	return (0);
    117 }
    118 
    119 static void
    120 ikphyattach(struct device *parent, struct device *self, void *aux)
    121 {
    122 	struct mii_softc *sc = device_private(self);
    123 	struct mii_attach_args *ma = aux;
    124 	struct mii_data *mii = ma->mii_data;
    125 	const struct mii_phydesc *mpd;
    126 
    127 	mpd = mii_phy_match(ma, ikphys);
    128 	aprint_naive(": Media interface\n");
    129 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
    130 
    131 	sc->mii_inst = mii->mii_instance;
    132 	sc->mii_phy = ma->mii_phyno;
    133 	sc->mii_funcs = &ikphy_funcs;
    134 	sc->mii_pdata = mii;
    135 	sc->mii_flags = ma->mii_flags;
    136 	sc->mii_anegticks = MII_ANEGTICKS;
    137 
    138 	PHY_RESET(sc);
    139 
    140 	sc->mii_capabilities =
    141 	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
    142 	if (sc->mii_capabilities & BMSR_EXTSTAT)
    143 	    sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
    144 	aprint_normal("%s: ", sc->mii_dev.dv_xname);
    145 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
    146 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
    147 		aprint_error("no media present");
    148 	else
    149 		mii_phy_add_media(sc);
    150 	aprint_normal("\n");
    151 }
    152 
    153 static int
    154 ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
    155 {
    156 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    157 	int reg;
    158 
    159 	if (!device_is_active(&sc->mii_dev))
    160 		return (ENXIO);
    161 
    162 	switch (cmd) {
    163 	case MII_POLLSTAT:
    164 		/*
    165 		 * If we're not polling our PHY instance, just return.
    166 		 */
    167 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    168 			return (0);
    169 		break;
    170 
    171 	case MII_MEDIACHG:
    172 		/*
    173 		 * If the media indicates a different PHY instance,
    174 		 * isolate ourselves.
    175 		 */
    176 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
    177 			reg = PHY_READ(sc, MII_BMCR);
    178 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
    179 			return (0);
    180 		}
    181 
    182 		/*
    183 		 * If the interface is not up, don't do anything.
    184 		 */
    185 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
    186 			break;
    187 
    188 		ikphy_setmedia(sc);
    189 		break;
    190 
    191 	case MII_TICK:
    192 		/*
    193 		 * If we're not currently selected, just return.
    194 		 */
    195 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    196 			return (0);
    197 
    198 		if (mii_phy_tick(sc) == EJUSTRETURN)
    199 			return (0);
    200 		break;
    201 
    202 	case MII_DOWN:
    203 		mii_phy_down(sc);
    204 		return (0);
    205 	}
    206 
    207 	/* Update the media status. */
    208 	mii_phy_status(sc);
    209 
    210 	/* Callback if something changed. */
    211 	mii_phy_update(sc, cmd);
    212 	return (0);
    213 }
    214 
    215 static void
    216 ikphy_setmedia(struct mii_softc *sc)
    217 {
    218 	uint16_t phy_data;
    219 	struct mii_data *mii = sc->mii_pdata;
    220 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    221 
    222 	/* Enable CRS on TX for half-duplex operation. */
    223 	phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL);
    224 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
    225 	/* Use 25MHz for both link down and 1000BASE-T for Tx clock */
    226 	phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
    227 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
    228 
    229 	/* set mdi/mid-x options */
    230 	phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL);
    231 	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
    232 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
    233 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
    234 	else
    235 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
    236 	/* set polarity correction */
    237 	phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
    238 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data);
    239 
    240 	/* SW Reset the PHY so all changes take effect */
    241 	PHY_RESET(sc);
    242 
    243 	/* for the i80003 */
    244 	phy_data = PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2);
    245 	phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
    246 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data);
    247 
    248 	/* Enable Electrical Idle on the PHY */
    249 	phy_data = PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL);
    250 	phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
    251 	PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data);
    252 
    253 	phy_data = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL);
    254 	phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
    255 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data);
    256 
    257 	/*
    258 	 * Workaround: Disable padding in Kumeran interface in the MAC
    259 	 * and in the PHY to avoid CRC errors.
    260 	 */
    261 	phy_data = PHY_READ(sc, GG82563_PHY_INBAND_CTRL);
    262 	phy_data |= GG82563_ICR_DIS_PADDING;
    263 	PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data);
    264 
    265 	mii_phy_setmedia(sc);
    266 	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
    267 		/*
    268 		 * when not in auto mode, we need to restart nego
    269 		 * anyway, or a switch from a fixed mode to another
    270 		 * fixed mode may not be seen by the switch.
    271 		 */
    272 		PHY_WRITE(sc, MII_BMCR,
    273 		    PHY_READ(sc, MII_BMCR) | BMCR_STARTNEG);
    274 	}
    275 	phy_data = PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL);
    276 	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
    277 	switch(IFM_SUBTYPE(ife->ifm_media)) {
    278 	case IFM_10_T:
    279 		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
    280 		break;
    281 	case IFM_100_TX:
    282 		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
    283 		break;
    284 	case IFM_1000_T:
    285 		phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
    286 		break;
    287 	}
    288 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
    289 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
    290 }
    291 
    292 static void
    293 ikphy_status(struct mii_softc *sc)
    294 {
    295 	struct mii_data *mii = sc->mii_pdata;
    296 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    297 	int pssr, bmcr, gtsr, kmrn;
    298 
    299 	mii->mii_media_status = IFM_AVALID;
    300 	mii->mii_media_active = IFM_ETHER;
    301 
    302 	pssr = PHY_READ(sc, GG82563_PHY_SPEC_STATUS);
    303 
    304 	if (pssr & GG82563_PSSR_LINK)
    305 		mii->mii_media_status |= IFM_ACTIVE;
    306 
    307 	bmcr = PHY_READ(sc, MII_BMCR);
    308 	if (bmcr & BMCR_ISO) {
    309 		mii->mii_media_active |= IFM_NONE;
    310 		mii->mii_media_status = 0;
    311 		return;
    312 	}
    313 
    314 	if (bmcr & BMCR_LOOP)
    315 		mii->mii_media_active |= IFM_LOOP;
    316 
    317 	if (bmcr & BMCR_AUTOEN) {
    318 		/*
    319 		 * The media status bits are only valid of autonegotiation
    320 		 * has completed (or it's disabled).
    321 		 */
    322 		if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) {
    323 			/* Erg, still trying, I guess... */
    324 			mii->mii_media_active |= IFM_NONE;
    325 			return;
    326 		}
    327 
    328 		switch (pssr & GG82563_PSSR_SPEED_MASK) {
    329 		case GG82563_PSSR_SPEED_1000MBPS:
    330 			mii->mii_media_active |= IFM_1000_T;
    331 			gtsr = PHY_READ(sc, MII_100T2SR);
    332 			if (gtsr & GTSR_MS_RES)
    333 				mii->mii_media_active |= IFM_ETH_MASTER;
    334 			break;
    335 
    336 		case GG82563_PSSR_SPEED_100MBPS:
    337 			mii->mii_media_active |= IFM_100_TX;
    338 			break;
    339 
    340 		case GG82563_PSSR_SPEED_10MBPS:
    341 			mii->mii_media_active |= IFM_10_T;
    342 			break;
    343 
    344 		default:
    345 			mii->mii_media_active |= IFM_NONE;
    346 			mii->mii_media_status = 0;
    347 			return;
    348 		}
    349 
    350 		if (pssr & GG82563_PSSR_DUPLEX)
    351 			mii->mii_media_active |=
    352 			    IFM_FDX | mii_phy_flowstatus(sc);
    353 	} else
    354 		mii->mii_media_active = ife->ifm_media;
    355 	kmrn = PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL);
    356 	if (mii->mii_media_active & IFM_FDX)
    357 		kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
    358 	else
    359 		kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER;
    360 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn);
    361 }
    362