Home | History | Annotate | Line # | Download | only in mii
      1 /*	$NetBSD: micphy.c,v 1.15 2022/10/31 22:45:13 jmcneill Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center, and by Frank van der Linden.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Copyright (c) 1997 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 Micrel KSZ8xxx 10/100 and KSZ9xxx 10/100/1000 PHY.
     59  */
     60 
     61 #include <sys/cdefs.h>
     62 __KERNEL_RCSID(0, "$NetBSD: micphy.c,v 1.15 2022/10/31 22:45:13 jmcneill Exp $");
     63 
     64 #include "opt_mii.h"
     65 
     66 #include <sys/param.h>
     67 #include <sys/systm.h>
     68 #include <sys/kernel.h>
     69 #include <sys/device.h>
     70 #include <sys/socket.h>
     71 #include <sys/errno.h>
     72 
     73 #include <net/if.h>
     74 #include <net/if_media.h>
     75 
     76 #include <dev/mii/mii.h>
     77 #include <dev/mii/miivar.h>
     78 #include <dev/mii/miidevs.h>
     79 
     80 static int	micphymatch(device_t, cfdata_t, void *);
     81 static void	micphyattach(device_t, device_t, void *);
     82 static void	micphy_reset(struct mii_softc *);
     83 static int	micphy_service(struct mii_softc *, struct mii_data *, int);
     84 
     85 CFATTACH_DECL_NEW(micphy, sizeof(struct mii_softc),
     86     micphymatch, micphyattach, mii_phy_detach, mii_phy_activate);
     87 
     88 static int	micphy_service(struct mii_softc *, struct mii_data *, int);
     89 static void	micphy_status(struct mii_softc *);
     90 static void	micphy_fixup(struct mii_softc *, int, int, device_t);
     91 
     92 static const struct mii_phy_funcs micphy_funcs = {
     93 	micphy_service, micphy_status, micphy_reset,
     94 };
     95 
     96 struct micphy_softc {
     97 	struct mii_softc sc_mii;
     98 	uint32_t sc_lstype;	/* Type of link status register */
     99 };
    100 
    101 static const struct mii_phydesc micphys[] = {
    102 	MII_PHY_DESC(MICREL, KSZ8041),
    103 	MII_PHY_DESC(MICREL, KSZ8051), /* +8021,8031 */
    104 	MII_PHY_DESC(MICREL, KSZ8061),
    105 	MII_PHY_DESC(MICREL, KSZ8081), /* +8051,8091 */
    106 	MII_PHY_DESC(MICREL, KS8737),
    107 	MII_PHY_DESC(MICREL, KSZ9021_8001_8721),
    108 	MII_PHY_DESC(MICREL, KSZ9031),
    109 	MII_PHY_DESC(MICREL, KSZ9131),
    110 	MII_PHY_DESC(MICREL, KSZ9477), /* +LAN7430internal */
    111 	MII_PHY_END,
    112 };
    113 
    114 /*
    115  * Model Rev. Media  LSTYPE Devices
    116  *
    117  * 0x11	      100    1F_42  KSZ8041
    118  * 0x13	      100    1F_42? KSZ8041RNLI
    119  * 0x15	   ?  100    1E_20  KSZ8051
    120  * 	 0x5  100    1E_20  KSZ8021
    121  * 	 0x6  100    1E_20  KSZ8031
    122  * 0x16	   ?  100    1E_20  KSZ8081
    123  * 	   ?  100    1E_20  KSZ8091
    124  * 0x17	      100    1E_20  KSZ8061
    125  * 0x21	 0x0  giga   GIGA   KSZ9021
    126  * 	 0x1  giga   GIGA   KSZ9021RLRN
    127  * 	 0x9  100    1F_42  KSZ8721BL/SL
    128  * 	 0x9  100    none?  KSZ8721CL
    129  * 	 0xa  100    1F_42  KSZ8001
    130  * 0x22	      giga   GIGA   KSZ9031
    131  * 0x23	   1? gigasw GIGA   KSZ9477 (No master/slave bit)
    132  * 	   5? giga   GIGA   LAN7430internal
    133  * 0x24	      giga   GIGA   KSZ9131
    134  * 0x32	      100    1F_42  KS8737
    135  */
    136 
    137 /* Type of link status register */
    138 #define MICPHYF_LSTYPE_DEFAULT	0
    139 #define MICPHYF_LSTYPE_1F_42	1
    140 #define MICPHYF_LSTYPE_1E_20	2
    141 #define MICPHYF_LSTYPE_GIGA	3
    142 
    143 /* Return if the device is Gigabit (KSZ9021) */
    144 #define KSZ_MODEL21H_GIGA(rev)			\
    145 	((((rev) & 0x0e) == 0) ? true : false)
    146 
    147 #define KSZ_XREG_CONTROL	0x0b
    148 #define KSZ_XREG_WRITE		0x0c
    149 #define KSZ_XREG_READ		0x0d
    150 #define KSZ_XREG_CTL_SEL_READ	0x0000
    151 #define KSZ_XREG_CTL_SEL_WRITE	0x8000
    152 
    153 #define REG_RGMII_CLOCK_AND_CONTROL	0x104
    154 #define REG_RGMII_RX_DATA		0x105
    155 
    156 /* PHY control 1 register for 10/100 PHYs (KSZ80[235689]1) */
    157 #define KSZ8051_PHYCTL1		0x1e
    158 #define KSZ8051_PHY_LINK	0x0100
    159 #define KSZ8051_PHY_MDIX	0x0020
    160 #define KSZ8051_PHY_FDX		0x0004
    161 #define KSZ8051_PHY_SPD_MASK	0x0003
    162 #define KSZ8051_PHY_SPD_10T	0x0001
    163 #define KSZ8051_PHY_SPD_100TX	0x0002
    164 
    165 /* PHY control 2 register for 10/100 PHYs (KSZ8041, KSZ8721 and KSZ8001) */
    166 #define	KSZ8041_PHYCTL2		0x1f
    167 #define KSZ8041_PHY_ACOMP	0x0080
    168 #define KSZ8041_PHY_SPD_MASK	0x001c
    169 #define KSZ8041_PHY_SPD_10T	0x0004
    170 #define KSZ8041_PHY_SPD_100TX	0x0008
    171 #define KSZ8041_PHY_FDX		0x0010
    172 #define KSZ8051_PHYCTL2		0x1f
    173 
    174 /* PHY control register for Gigabit PHYs */
    175 #define KSZ_GPHYCTL		0x1f
    176 #define KSZ_GPHY_SPD_1000T	0x0040
    177 #define KSZ_GPHY_SPD_100TX	0x0020
    178 #define KSZ_GPHY_SPD_10T	0x0010
    179 #define KSZ_GPHY_FDX		0x0008
    180 #define KSZ_GPHY_1000T_MS	0x0004
    181 
    182 static int
    183 micphymatch(device_t parent, cfdata_t match, void *aux)
    184 {
    185 	struct mii_attach_args *ma = aux;
    186 
    187 	if (mii_phy_match(ma, micphys) != NULL)
    188 		return 10;
    189 
    190 	return 1;
    191 }
    192 
    193 static void
    194 micphyattach(device_t parent, device_t self, void *aux)
    195 {
    196 	struct micphy_softc *msc = device_private(self);
    197 	struct mii_softc *sc = &msc->sc_mii;
    198 	struct mii_attach_args *ma = aux;
    199 	struct mii_data *mii = ma->mii_data;
    200 	int model = MII_MODEL(ma->mii_id2);
    201 	int rev = MII_REV(ma->mii_id2);
    202 	const struct mii_phydesc *mpd;
    203 
    204 	mpd = mii_phy_match(ma, micphys);
    205 	aprint_naive(": Media interface\n");
    206 	aprint_normal(": %s, rev. %d\n", mpd->mpd_name, rev);
    207 
    208 	sc->mii_dev = self;
    209 	sc->mii_inst = mii->mii_instance;
    210 	sc->mii_phy = ma->mii_phyno;
    211 	sc->mii_funcs = &micphy_funcs;
    212 	sc->mii_pdata = mii;
    213 	sc->mii_flags = ma->mii_flags;
    214 
    215 	if ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8041)
    216 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8041RNLI)
    217 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KS8737)
    218 	    || ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9021_8001_8721)
    219 		&& !KSZ_MODEL21H_GIGA(sc->mii_mpd_rev))) {
    220 		msc->sc_lstype = MICPHYF_LSTYPE_1F_42;
    221 	} else if ((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8051)
    222 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
    223 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8061)) {
    224 		msc->sc_lstype = MICPHYF_LSTYPE_1E_20;
    225 	} else if (((sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9021_8001_8721)
    226 		&& KSZ_MODEL21H_GIGA(sc->mii_mpd_rev))
    227 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9031)
    228 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9477)
    229 	    || (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ9131)) {
    230 		msc->sc_lstype = MICPHYF_LSTYPE_GIGA;
    231 	} else
    232 		msc->sc_lstype = MICPHYF_LSTYPE_DEFAULT;
    233 
    234 	mii_lock(mii);
    235 
    236 	PHY_RESET(sc);
    237 
    238 	micphy_fixup(sc, model, rev, parent);
    239 
    240 	PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
    241 	sc->mii_capabilities &= ma->mii_capmask;
    242 	if (sc->mii_capabilities & BMSR_EXTSTAT)
    243 		PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
    244 
    245 	mii_unlock(mii);
    246 
    247 	mii_phy_add_media(sc);
    248 }
    249 
    250 static void
    251 micphy_reset(struct mii_softc *sc)
    252 {
    253 	uint16_t reg;
    254 
    255 	KASSERT(mii_locked(sc->mii_pdata));
    256 
    257 	/*
    258 	 * The 8081 has no "sticky bits" that survive a soft reset; several
    259 	 * bits in the Phy Control Register 2 must be preserved across the
    260 	 * reset. These bits are set up by the bootloader; they control how the
    261 	 * phy interfaces to the board (such as clock frequency and LED
    262 	 * behavior).
    263 	 */
    264 	if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
    265 		PHY_READ(sc, KSZ8051_PHYCTL2, &reg);
    266 	mii_phy_reset(sc);
    267 	if (sc->mii_mpd_model == MII_MODEL_MICREL_KSZ8081)
    268 		PHY_WRITE(sc, KSZ8051_PHYCTL2, reg);
    269 }
    270 
    271 static int
    272 micphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
    273 {
    274 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
    275 	uint16_t reg;
    276 
    277 	KASSERT(mii_locked(mii));
    278 
    279 	switch (cmd) {
    280 	case MII_POLLSTAT:
    281 		/* If we're not polling our PHY instance, just return. */
    282 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    283 			return 0;
    284 		break;
    285 
    286 	case MII_MEDIACHG:
    287 		/*
    288 		 * If the media indicates a different PHY instance,
    289 		 * isolate ourselves.
    290 		 */
    291 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
    292 			PHY_READ(sc, MII_BMCR, &reg);
    293 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
    294 			return 0;
    295 		}
    296 
    297 		/* If the interface is not up, don't do anything. */
    298 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
    299 			break;
    300 
    301 		mii_phy_setmedia(sc);
    302 		break;
    303 
    304 	case MII_TICK:
    305 		/* If we're not currently selected, just return. */
    306 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
    307 			return 0;
    308 
    309 		if (mii_phy_tick(sc) == EJUSTRETURN)
    310 			return 0;
    311 		break;
    312 
    313 	case MII_DOWN:
    314 		mii_phy_down(sc);
    315 		return 0;
    316 	}
    317 
    318 	/* Update the media status. */
    319 	mii_phy_status(sc);
    320 
    321 	/* Callback if something changed. */
    322 	mii_phy_update(sc, cmd);
    323 	return 0;
    324 }
    325 
    326 static void
    327 micphy_writexreg(struct mii_softc *sc, uint32_t reg, uint32_t wval)
    328 {
    329 	uint16_t rval __debugused;
    330 
    331 	PHY_WRITE(sc, KSZ_XREG_CONTROL, KSZ_XREG_CTL_SEL_WRITE | reg);
    332 	PHY_WRITE(sc, KSZ_XREG_WRITE, wval);
    333 	PHY_WRITE(sc, KSZ_XREG_CONTROL, KSZ_XREG_CTL_SEL_READ | reg);
    334 	PHY_READ(sc, KSZ_XREG_READ, &rval);
    335 	KDASSERT(wval == rval);
    336 }
    337 
    338 static void
    339 micphy_fixup(struct mii_softc *sc, int model, int rev, device_t parent)
    340 {
    341 
    342 	KASSERT(mii_locked(sc->mii_pdata));
    343 
    344 	switch (model) {
    345 	case MII_MODEL_MICREL_KSZ9021_8001_8721:
    346 		if (!device_is_a(parent, "cpsw"))
    347 			break;
    348 
    349 		aprint_normal_dev(sc->mii_dev,
    350 		    "adjusting RGMII signal timing for cpsw\n");
    351 
    352 		// RGMII RX Data Pad Skew
    353 		micphy_writexreg(sc, REG_RGMII_RX_DATA, 0x0000);
    354 
    355 		// RGMII Clock and Control Pad Skew
    356 		micphy_writexreg(sc, REG_RGMII_CLOCK_AND_CONTROL, 0x9090);
    357 
    358 		break;
    359 	default:
    360 		break;
    361 	}
    362 
    363 	return;
    364 }
    365 
    366 static void
    367 micphy_status(struct mii_softc *sc)
    368 {
    369 	struct micphy_softc *msc = device_private(sc->mii_dev);
    370 	struct mii_data *mii = sc->mii_pdata;
    371 	uint16_t bmsr, bmcr, sr;
    372 
    373 	KASSERT(mii_locked(mii));
    374 
    375 	/* For unknown devices */
    376 	if (msc->sc_lstype == MICPHYF_LSTYPE_DEFAULT) {
    377 		ukphy_status(sc);
    378 		return;
    379 	}
    380 
    381 	mii->mii_media_status = IFM_AVALID;
    382 	mii->mii_media_active = IFM_ETHER;
    383 
    384 	PHY_READ(sc, MII_BMCR, &bmcr);
    385 
    386 	PHY_READ(sc, MII_BMSR, &bmsr);
    387 	PHY_READ(sc, MII_BMSR, &bmsr);
    388 	if (bmsr & BMSR_LINK)
    389 		mii->mii_media_status |= IFM_ACTIVE;
    390 
    391 	if (bmcr & BMCR_AUTOEN) {
    392 		if ((bmsr & BMSR_ACOMP) == 0) {
    393 			mii->mii_media_active |= IFM_NONE;
    394 			return;
    395 		}
    396 	}
    397 
    398 	if (msc->sc_lstype == MICPHYF_LSTYPE_1F_42) {
    399 		PHY_READ(sc, KSZ8041_PHYCTL2, &sr);
    400 		if ((sr & KSZ8041_PHY_SPD_MASK) == 0)
    401 			mii->mii_media_active |= IFM_NONE;
    402 		else if (sr & KSZ8041_PHY_SPD_100TX)
    403 			mii->mii_media_active |= IFM_100_TX;
    404 		else if (sr & KSZ8041_PHY_SPD_10T)
    405 			mii->mii_media_active |= IFM_10_T;
    406 		if (sr & KSZ8041_PHY_FDX)
    407 			mii->mii_media_active |= IFM_FDX
    408 			    | mii_phy_flowstatus(sc);
    409 	} else if (msc->sc_lstype == MICPHYF_LSTYPE_1E_20) {
    410 		PHY_READ(sc, KSZ8051_PHYCTL1, &sr);
    411 		if ((sr & KSZ8051_PHY_SPD_MASK) == 0)
    412 			mii->mii_media_active |= IFM_NONE;
    413 		else if (sr & KSZ8051_PHY_SPD_100TX)
    414 			mii->mii_media_active |= IFM_100_TX;
    415 		else if (sr & KSZ8051_PHY_SPD_10T)
    416 			mii->mii_media_active |= IFM_10_T;
    417 		if (sr & KSZ8051_PHY_FDX)
    418 			mii->mii_media_active |= IFM_FDX
    419 			    | mii_phy_flowstatus(sc);
    420 	} else if (msc->sc_lstype == MICPHYF_LSTYPE_GIGA) {
    421 		/* 9021/9031/7430/9131 gphy */
    422 		PHY_READ(sc, KSZ_GPHYCTL, &sr);
    423 		if (sr & KSZ_GPHY_SPD_1000T)
    424 			mii->mii_media_active |= IFM_1000_T;
    425 		else if (sr & KSZ_GPHY_SPD_100TX)
    426 			mii->mii_media_active |= IFM_100_TX;
    427 		else if (sr & KSZ_GPHY_SPD_10T)
    428 			mii->mii_media_active |= IFM_10_T;
    429 		else
    430 			mii->mii_media_active |= IFM_NONE;
    431 		if ((mii->mii_media_active & IFM_1000_T)
    432 		    && (sr & KSZ_GPHY_1000T_MS))
    433 			mii->mii_media_active |= IFM_ETH_MASTER;
    434 		if (sr & KSZ_GPHY_FDX)
    435 			mii->mii_media_active |= IFM_FDX
    436 			    | mii_phy_flowstatus(sc);
    437 		else
    438 			mii->mii_media_active |= IFM_HDX;
    439 	}
    440 }
    441