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