Home | History | Annotate | Line # | Download | only in mii
ikphy.c revision 1.13
      1 /*	$NetBSD: ikphy.c,v 1.13 2019/01/22 03:42:27 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.13 2019/01/22 03:42:27 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_OUI_xxMARVELL,		MII_MODEL_xxMARVELL_I82563,
     96 	  MII_STR_xxMARVELL_I82563 },
     97 
     98 	{ 0,				0,
     99 	  NULL },
    100 };
    101 
    102 static int
    103 ikphymatch(device_t parent, cfdata_t match, void *aux)
    104 {
    105 	struct mii_attach_args *ma = aux;
    106 
    107 	if (mii_phy_match(ma, ikphys) != NULL)
    108 		return (10);
    109 
    110 	return (0);
    111 }
    112 
    113 static void
    114 ikphyattach(device_t parent, device_t self, void *aux)
    115 {
    116 	struct mii_softc *sc = device_private(self);
    117 	struct mii_attach_args *ma = aux;
    118 	struct mii_data *mii = ma->mii_data;
    119 	const struct mii_phydesc *mpd;
    120 
    121 	mpd = mii_phy_match(ma, ikphys);
    122 	aprint_naive(": Media interface\n");
    123 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
    124 
    125 	sc->mii_dev = self;
    126 	sc->mii_inst = mii->mii_instance;
    127 	sc->mii_phy = ma->mii_phyno;
    128 	sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
    129 	sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
    130 	sc->mii_mpd_rev = MII_REV(ma->mii_id2);
    131 	sc->mii_funcs = &ikphy_funcs;
    132 	sc->mii_pdata = mii;
    133 	sc->mii_flags = ma->mii_flags;
    134 	sc->mii_anegticks = MII_ANEGTICKS;
    135 
    136 	PHY_RESET(sc);
    137 
    138 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
    139 	sc->mii_capabilities &= ma->mii_capmask;
    140 	if (sc->mii_capabilities & BMSR_EXTSTAT)
    141 		PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
    142 	aprint_normal_dev(self, "");
    143 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
    144 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
    145 		aprint_error("no media present");
    146 	else
    147 		mii_phy_add_media(sc);
    148 	aprint_normal("\n");
    149 }
    150 
    151 static int
    152 ikphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
    153 {
    154 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    155 	uint16_t reg;
    156 
    157 	switch (cmd) {
    158 	case MII_POLLSTAT:
    159 		/*
    160 		 * If we're not polling our PHY instance, just return.
    161 		 */
    162 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    163 			return (0);
    164 		break;
    165 
    166 	case MII_MEDIACHG:
    167 		/*
    168 		 * If the media indicates a different PHY instance,
    169 		 * isolate ourselves.
    170 		 */
    171 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
    172 			PHY_READ(sc, MII_BMCR, &reg);
    173 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
    174 			return (0);
    175 		}
    176 
    177 		/*
    178 		 * If the interface is not up, don't do anything.
    179 		 */
    180 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
    181 			break;
    182 
    183 		ikphy_setmedia(sc);
    184 		break;
    185 
    186 	case MII_TICK:
    187 		/*
    188 		 * If we're not currently selected, just return.
    189 		 */
    190 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    191 			return (0);
    192 
    193 		if (mii_phy_tick(sc) == EJUSTRETURN)
    194 			return (0);
    195 		break;
    196 
    197 	case MII_DOWN:
    198 		mii_phy_down(sc);
    199 		return (0);
    200 	}
    201 
    202 	/* Update the media status. */
    203 	mii_phy_status(sc);
    204 
    205 	/* Callback if something changed. */
    206 	mii_phy_update(sc, cmd);
    207 	return (0);
    208 }
    209 
    210 static void
    211 ikphy_setmedia(struct mii_softc *sc)
    212 {
    213 	uint16_t phy_data;
    214 	struct mii_data *mii = sc->mii_pdata;
    215 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    216 
    217 	/* Enable CRS on TX for half-duplex operation. */
    218 	PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
    219 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
    220 	/* Use 25MHz for both link down and 1000BASE-T for Tx clock */
    221 	phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
    222 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
    223 
    224 	/* set mdi/mid-x options */
    225 	PHY_READ(sc, GG82563_PHY_SPEC_CTRL, &phy_data);
    226 	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
    227 	if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO)
    228 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
    229 	else
    230 		phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
    231 	/* set polarity correction */
    232 	phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
    233 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL, phy_data);
    234 
    235 	/* SW Reset the PHY so all changes take effect */
    236 	PHY_RESET(sc);
    237 
    238 	/* for the i80003 */
    239 	PHY_READ(sc, GG82563_PHY_SPEC_CTRL_2, &phy_data);
    240 	phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
    241 	PHY_WRITE(sc, GG82563_PHY_SPEC_CTRL_2, phy_data);
    242 
    243 	/* Enable Electrical Idle on the PHY */
    244 	PHY_READ(sc, GG82563_PHY_PWR_MGMT_CTRL, &phy_data);
    245 	phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
    246 	PHY_WRITE(sc, GG82563_PHY_PWR_MGMT_CTRL, phy_data);
    247 
    248 	PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &phy_data);
    249 	phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
    250 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, phy_data);
    251 
    252 	/*
    253 	 * Workaround: Disable padding in Kumeran interface in the MAC
    254 	 * and in the PHY to avoid CRC errors.
    255 	 */
    256 	PHY_READ(sc, GG82563_PHY_INBAND_CTRL, &phy_data);
    257 	phy_data |= GG82563_ICR_DIS_PADDING;
    258 	PHY_WRITE(sc, GG82563_PHY_INBAND_CTRL, phy_data);
    259 
    260 	mii_phy_setmedia(sc);
    261 	if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
    262 		/*
    263 		 * when not in auto mode, we need to restart nego
    264 		 * anyway, or a switch from a fixed mode to another
    265 		 * fixed mode may not be seen by the switch.
    266 		 */
    267 		PHY_READ(sc, MII_BMCR, &phy_data);
    268 		PHY_WRITE(sc, MII_BMCR, phy_data | BMCR_STARTNEG);
    269 	}
    270 	PHY_READ(sc, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
    271 	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
    272 	switch(IFM_SUBTYPE(ife->ifm_media)) {
    273 	case IFM_10_T:
    274 		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ;
    275 		break;
    276 	case IFM_100_TX:
    277 		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ;
    278 		break;
    279 	case IFM_1000_T:
    280 		phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ;
    281 		break;
    282 	}
    283 	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
    284 	PHY_WRITE(sc, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
    285 }
    286 
    287 static void
    288 ikphy_status(struct mii_softc *sc)
    289 {
    290 	struct mii_data *mii = sc->mii_pdata;
    291 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    292 	uint16_t pssr, bmcr, gtsr, kmrn;
    293 
    294 	mii->mii_media_status = IFM_AVALID;
    295 	mii->mii_media_active = IFM_ETHER;
    296 
    297 	PHY_READ(sc, GG82563_PHY_SPEC_STATUS, &pssr);
    298 
    299 	if (pssr & GG82563_PSSR_LINK)
    300 		mii->mii_media_status |= IFM_ACTIVE;
    301 
    302 	PHY_READ(sc, MII_BMCR, &bmcr);
    303 	if (bmcr & BMCR_ISO) {
    304 		mii->mii_media_active |= IFM_NONE;
    305 		mii->mii_media_status = 0;
    306 		return;
    307 	}
    308 
    309 	if (bmcr & BMCR_LOOP)
    310 		mii->mii_media_active |= IFM_LOOP;
    311 
    312 	if (bmcr & BMCR_AUTOEN) {
    313 		/*
    314 		 * The media status bits are only valid of autonegotiation
    315 		 * has completed (or it's disabled).
    316 		 */
    317 		if ((pssr & GG82563_PSSR_SPEED_DUPLEX_RESOLVED) == 0) {
    318 			/* Erg, still trying, I guess... */
    319 			mii->mii_media_active |= IFM_NONE;
    320 			return;
    321 		}
    322 
    323 		switch (pssr & GG82563_PSSR_SPEED_MASK) {
    324 		case GG82563_PSSR_SPEED_1000MBPS:
    325 			mii->mii_media_active |= IFM_1000_T;
    326 			PHY_READ(sc, MII_100T2SR, &gtsr);
    327 			if (gtsr & GTSR_MS_RES)
    328 				mii->mii_media_active |= IFM_ETH_MASTER;
    329 			break;
    330 
    331 		case GG82563_PSSR_SPEED_100MBPS:
    332 			mii->mii_media_active |= IFM_100_TX;
    333 			break;
    334 
    335 		case GG82563_PSSR_SPEED_10MBPS:
    336 			mii->mii_media_active |= IFM_10_T;
    337 			break;
    338 
    339 		default:
    340 			mii->mii_media_active |= IFM_NONE;
    341 			mii->mii_media_status = 0;
    342 			return;
    343 		}
    344 
    345 		if (pssr & GG82563_PSSR_DUPLEX)
    346 			mii->mii_media_active |=
    347 			    IFM_FDX | mii_phy_flowstatus(sc);
    348 		else
    349 			mii->mii_media_active |= IFM_HDX;
    350 	} else
    351 		mii->mii_media_active = ife->ifm_media;
    352 	PHY_READ(sc, GG82563_PHY_KMRN_MODE_CTRL, &kmrn);
    353 	if (mii->mii_media_active & IFM_FDX)
    354 		kmrn &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
    355 	else
    356 		kmrn |= GG82563_KMCR_PASS_FALSE_CARRIER;
    357 	PHY_WRITE(sc, GG82563_PHY_KMRN_MODE_CTRL, kmrn);
    358 }
    359